1 /*
2  * Polling/timing management
3  * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #define FP_COMPONENT "poll"
21 
22 #include <config.h>
23 #include <errno.h>
24 #include <time.h>
25 #include <sys/time.h>
26 
27 #include <glib.h>
28 #include <libusb.h>
29 
30 #include "fp_internal.h"
31 
32 /**
33  * @defgroup poll Polling and timing operations
34  * These functions are only applicable to users of libfprint's asynchronous
35  * API.
36  *
37  * libfprint does not create internal library threads and hence can only
38  * execute when your application is calling a libfprint function. However,
39  * libfprint often has work to be do, such as handling of completed USB
40  * transfers, and processing of timeouts required in order for the library
41  * to function. Therefore it is essential that your own application must
42  * regularly "phone into" libfprint so that libfprint can handle any pending
43  * events.
44  *
45  * The function you must call is fp_handle_events() or a variant of it. This
46  * function will handle any pending events, and it is from this context that
47  * all asynchronous event callbacks from the library will occur. You can view
48  * this function as a kind of iteration function.
49  *
50  * If there are no events pending, fp_handle_events() will block for a few
51  * seconds (and will handle any new events should anything occur in that time).
52  * If you wish to customise this timeout, you can use
53  * fp_handle_events_timeout() instead. If you wish to do a nonblocking
54  * iteration, call fp_handle_events_timeout() with a zero timeout.
55  *
56  * TODO: document how application is supposed to know when to call these
57  * functions.
58  */
59 
60 /* this is a singly-linked list of pending timers, sorted with the timer that
61  * is expiring soonest at the head. */
62 static GSList *active_timers = NULL;
63 
64 /* notifiers for added or removed poll fds */
65 static fp_pollfd_added_cb fd_added_cb = NULL;
66 static fp_pollfd_removed_cb fd_removed_cb = NULL;
67 
68 struct fpi_timeout {
69 	struct timeval expiry;
70 	fpi_timeout_fn callback;
71 	void *data;
72 };
73 
timeout_sort_fn(gconstpointer _a,gconstpointer _b)74 static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
75 {
76 	struct fpi_timeout *a = (struct fpi_timeout *) _a;
77 	struct fpi_timeout *b = (struct fpi_timeout *) _b;
78 	struct timeval *tv_a = &a->expiry;
79 	struct timeval *tv_b = &b->expiry;
80 
81 	if (timercmp(tv_a, tv_b, <))
82 		return -1;
83 	else if (timercmp(tv_a, tv_b, >))
84 		return 1;
85 	else
86 		return 0;
87 }
88 
89 /* A timeout is the asynchronous equivalent of sleeping. You create a timeout
90  * saying that you'd like to have a function invoked at a certain time in
91  * the future. */
fpi_timeout_add(unsigned int msec,fpi_timeout_fn callback,void * data)92 struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback,
93 	void *data)
94 {
95 	struct timespec ts;
96 	struct timeval add_msec;
97 	struct fpi_timeout *timeout;
98 	int r;
99 
100 	fp_dbg("in %dms", msec);
101 
102 	r = clock_gettime(CLOCK_MONOTONIC, &ts);
103 	if (r < 0) {
104 		fp_err("failed to read monotonic clock, errno=%d", errno);
105 		return NULL;
106 	}
107 
108 	timeout = g_malloc(sizeof(*timeout));
109 	timeout->callback = callback;
110 	timeout->data = data;
111 	TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts);
112 
113 	/* calculate timeout expiry by adding delay to current monotonic clock */
114 	timerclear(&add_msec);
115 	add_msec.tv_sec = msec / 1000;
116 	add_msec.tv_usec = (msec % 1000) * 1000;
117 	timeradd(&timeout->expiry, &add_msec, &timeout->expiry);
118 
119 	active_timers = g_slist_insert_sorted(active_timers, timeout,
120 		timeout_sort_fn);
121 
122 	return timeout;
123 }
124 
fpi_timeout_cancel(struct fpi_timeout * timeout)125 void fpi_timeout_cancel(struct fpi_timeout *timeout)
126 {
127 	fp_dbg("");
128 	active_timers = g_slist_remove(active_timers, timeout);
129 	g_free(timeout);
130 }
131 
132 /* get the expiry time and optionally the timeout structure for the next
133  * timeout. returns 0 if there are no expired timers, or 1 if the
134  * timeval/timeout output parameters were populated. if the returned timeval
135  * is zero then it means the timeout has already expired and should be handled
136  * ASAP. */
get_next_timeout_expiry(struct timeval * out,struct fpi_timeout ** out_timeout)137 static int get_next_timeout_expiry(struct timeval *out,
138 	struct fpi_timeout **out_timeout)
139 {
140 	struct timespec ts;
141 	struct timeval tv;
142 	struct fpi_timeout *next_timeout;
143 	int r;
144 
145 	if (active_timers == NULL)
146 		return 0;
147 
148 	r = clock_gettime(CLOCK_MONOTONIC, &ts);
149 	if (r < 0) {
150 		fp_err("failed to read monotonic clock, errno=%d", errno);
151 		return r;
152 	}
153 	TIMESPEC_TO_TIMEVAL(&tv, &ts);
154 
155 	next_timeout = active_timers->data;
156 	if (out_timeout)
157 		*out_timeout = next_timeout;
158 
159 	if (timercmp(&tv, &next_timeout->expiry, >=)) {
160 		fp_dbg("first timeout already expired");
161 		timerclear(out);
162 	} else {
163 		timersub(&next_timeout->expiry, &tv, out);
164 		fp_dbg("next timeout in %d.%06ds", out->tv_sec, out->tv_usec);
165 	}
166 
167 	return 1;
168 }
169 
170 /* handle a timeout that has expired */
handle_timeout(struct fpi_timeout * timeout)171 static void handle_timeout(struct fpi_timeout *timeout)
172 {
173 	fp_dbg("");
174 	timeout->callback(timeout->data);
175 	active_timers = g_slist_remove(active_timers, timeout);
176 	g_free(timeout);
177 }
178 
handle_timeouts(void)179 static int handle_timeouts(void)
180 {
181 	struct timeval next_timeout_expiry;
182 	struct fpi_timeout *next_timeout;
183 	int r;
184 
185 	r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
186 	if (r <= 0)
187 		return r;
188 
189 	if (!timerisset(&next_timeout_expiry))
190 		handle_timeout(next_timeout);
191 
192 	return 0;
193 }
194 
195 /** \ingroup poll
196  * Handle any pending events. If a non-zero timeout is specified, the function
197  * will potentially block for the specified amount of time, although it may
198  * return sooner if events have been handled. The function acts as non-blocking
199  * for a zero timeout.
200  *
201  * \param timeout Maximum timeout for this blocking function
202  * \returns 0 on success, non-zero on error.
203  */
fp_handle_events_timeout(struct timeval * timeout)204 API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout)
205 {
206 	struct timeval next_timeout_expiry;
207 	struct timeval select_timeout;
208 	struct fpi_timeout *next_timeout;
209 	int r;
210 
211 	r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
212 	if (r < 0)
213 		return r;
214 
215 	if (r) {
216 		/* timer already expired? */
217 		if (!timerisset(&next_timeout_expiry)) {
218 			handle_timeout(next_timeout);
219 			return 0;
220 		}
221 
222 		/* choose the smallest of next URB timeout or user specified timeout */
223 		if (timercmp(&next_timeout_expiry, timeout, <))
224 			select_timeout = next_timeout_expiry;
225 		else
226 			select_timeout = *timeout;
227 	} else {
228 		select_timeout = *timeout;
229 	}
230 
231 	r = libusb_handle_events_timeout(fpi_usb_ctx, &select_timeout);
232 	*timeout = select_timeout;
233 	if (r < 0)
234 		return r;
235 
236 	return handle_timeouts();
237 }
238 
239 /** \ingroup poll
240  * Convenience function for calling fp_handle_events_timeout() with a sensible
241  * default timeout value of two seconds (subject to change if we decide another
242  * value is more sensible).
243  *
244  * \returns 0 on success, non-zero on error.
245  */
fp_handle_events(void)246 API_EXPORTED int fp_handle_events(void)
247 {
248 	struct timeval tv;
249 	tv.tv_sec = 2;
250 	tv.tv_usec = 0;
251 	return fp_handle_events_timeout(&tv);
252 }
253 
254 /* FIXME: docs
255  * returns 0 if no timeouts active
256  * returns 1 if timeout returned
257  * zero timeout means events are to be handled immediately */
fp_get_next_timeout(struct timeval * tv)258 API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
259 {
260 	struct timeval fprint_timeout;
261 	struct timeval libusb_timeout;
262 	int r_fprint;
263 	int r_libusb;
264 
265 	r_fprint = get_next_timeout_expiry(&fprint_timeout, NULL);
266 	r_libusb = libusb_get_next_timeout(fpi_usb_ctx, &libusb_timeout);
267 
268 	/* if we have no pending timeouts and the same is true for libusb,
269 	 * indicate that we have no pending timouts */
270 	if (r_fprint == 0 && r_libusb == 0)
271 		return 0;
272 
273 	/* if fprint have no pending timeouts return libusb timeout */
274 	else if (r_fprint == 0)
275 		*tv = libusb_timeout;
276 
277 	/* if libusb have no pending timeouts return fprint timeout */
278 	else if (r_libusb == 0)
279 		*tv = fprint_timeout;
280 
281 	/* otherwise return the smaller of the 2 timeouts */
282 	else if (timercmp(&fprint_timeout, &libusb_timeout, <))
283 		*tv = fprint_timeout;
284 	else
285 		*tv = libusb_timeout;
286 	return 1;
287 }
288 
289 /** \ingroup poll
290  * Retrieve a list of file descriptors that should be polled for events
291  * interesting to libfprint. This function is only for users who wish to
292  * combine libfprint's file descriptor set with other event sources - more
293  * simplistic users will be able to call fp_handle_events() or a variant
294  * directly.
295  *
296  * \param pollfds output location for a list of pollfds. If non-NULL, must be
297  * released with free() when done.
298  * \returns the number of pollfds in the resultant list, or negative on error.
299  */
fp_get_pollfds(struct fp_pollfd ** pollfds)300 API_EXPORTED size_t fp_get_pollfds(struct fp_pollfd **pollfds)
301 {
302 	const struct libusb_pollfd **usbfds;
303 	const struct libusb_pollfd *usbfd;
304 	struct fp_pollfd *ret;
305 	size_t cnt = 0;
306 	size_t i = 0;
307 
308 	usbfds = libusb_get_pollfds(fpi_usb_ctx);
309 	if (!usbfds) {
310 		*pollfds = NULL;
311 		return -EIO;
312 	}
313 
314 	while ((usbfd = usbfds[i++]) != NULL)
315 		cnt++;
316 
317 	ret = g_malloc(sizeof(struct fp_pollfd) * cnt);
318 	i = 0;
319 	while ((usbfd = usbfds[i]) != NULL) {
320 		ret[i].fd = usbfd->fd;
321 		ret[i].events = usbfd->events;
322 		i++;
323 	}
324 
325 	*pollfds = ret;
326 	return cnt;
327 }
328 
329 /* FIXME: docs */
fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,fp_pollfd_removed_cb removed_cb)330 API_EXPORTED void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
331 	fp_pollfd_removed_cb removed_cb)
332 {
333 	fd_added_cb = added_cb;
334 	fd_removed_cb = removed_cb;
335 }
336 
add_pollfd(int fd,short events,void * user_data)337 static void add_pollfd(int fd, short events, void *user_data)
338 {
339 	if (fd_added_cb)
340 		fd_added_cb(fd, events);
341 }
342 
remove_pollfd(int fd,void * user_data)343 static void remove_pollfd(int fd, void *user_data)
344 {
345 	if (fd_removed_cb)
346 		fd_removed_cb(fd);
347 }
348 
fpi_poll_init(void)349 void fpi_poll_init(void)
350 {
351 	libusb_set_pollfd_notifiers(fpi_usb_ctx, add_pollfd, remove_pollfd, NULL);
352 }
353 
fpi_poll_exit(void)354 void fpi_poll_exit(void)
355 {
356 	g_slist_free(active_timers);
357 	active_timers = NULL;
358 	fd_added_cb = NULL;
359 	fd_removed_cb = NULL;
360 	libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL);
361 }
362 
363