1 /*
2 * fprint D-Bus daemon
3 * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "config.h"
21
22 #include <glib.h>
23 #include <libfprint/fprint.h>
24
25 #include <poll.h>
26 #include <stdlib.h>
27
28 #include "loop.h"
29
30 struct fdsource {
31 GSource source;
32 GSList *pollfds;
33 };
34
source_prepare(GSource * source,gint * timeout)35 static gboolean source_prepare(GSource *source, gint *timeout)
36 {
37 int r;
38 struct timeval tv;
39
40 r = fp_get_next_timeout(&tv);
41 if (r == 0) {
42 *timeout = -1;
43 return FALSE;
44 }
45
46 if (!timerisset(&tv))
47 return TRUE;
48
49 *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
50 return FALSE;
51 }
52
source_check(GSource * source)53 static gboolean source_check(GSource *source)
54 {
55 struct fdsource *_fdsource = (struct fdsource *) source;
56 GSList *l;
57 struct timeval tv;
58 int r;
59
60 if (!_fdsource->pollfds)
61 return FALSE;
62
63 for (l = _fdsource->pollfds; l != NULL; l = l->next) {
64 GPollFD *pollfd = l->data;
65
66 if (pollfd->revents)
67 return TRUE;
68 }
69
70 r = fp_get_next_timeout(&tv);
71 if (r == 1 && !timerisset(&tv))
72 return TRUE;
73
74 return FALSE;
75 }
76
source_dispatch(GSource * source,GSourceFunc callback,gpointer data)77 static gboolean source_dispatch(GSource *source, GSourceFunc callback,
78 gpointer data)
79 {
80 struct timeval zerotimeout = {
81 .tv_sec = 0,
82 .tv_usec = 0,
83 };
84
85 /* FIXME error handling */
86 fp_handle_events_timeout(&zerotimeout);
87
88 /* FIXME whats the return value used for? */
89 return TRUE;
90 }
91
source_finalize(GSource * source)92 static void source_finalize(GSource *source)
93 {
94 struct fdsource *_fdsource = (struct fdsource *) source;
95 GSList *l;
96
97 if (!_fdsource->pollfds)
98 return;
99
100 for (l = _fdsource->pollfds; l != NULL; l = l->next) {
101 GPollFD *pollfd = l->data;
102
103 g_source_remove_poll((GSource *) _fdsource, pollfd);
104 g_slice_free(GPollFD, pollfd);
105 _fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l);
106 }
107
108 g_slist_free(_fdsource->pollfds);
109 }
110
111 static GSourceFuncs sourcefuncs = {
112 .prepare = source_prepare,
113 .check = source_check,
114 .dispatch = source_dispatch,
115 .finalize = source_finalize,
116 };
117
118 static struct fdsource *fdsource = NULL;
119
pollfd_add(int fd,short events)120 static void pollfd_add(int fd, short events)
121 {
122 GPollFD *pollfd;
123
124 pollfd = g_slice_new(GPollFD);
125 pollfd->fd = fd;
126 pollfd->events = 0;
127 pollfd->revents = 0;
128 if (events & POLLIN)
129 pollfd->events |= G_IO_IN;
130 if (events & POLLOUT)
131 pollfd->events |= G_IO_OUT;
132
133 fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd);
134 g_source_add_poll((GSource *) fdsource, pollfd);
135 }
136
pollfd_added_cb(int fd,short events)137 static void pollfd_added_cb(int fd, short events)
138 {
139 g_debug("now monitoring fd %d", fd);
140 pollfd_add(fd, events);
141 }
142
pollfd_removed_cb(int fd)143 static void pollfd_removed_cb(int fd)
144 {
145 GSList *l;
146
147 g_debug("no longer monitoring fd %d", fd);
148
149 if (!fdsource->pollfds) {
150 g_debug("cannot remove from list as list is empty?");
151 return;
152 }
153
154 for (l = fdsource->pollfds; l != NULL; l = l->next) {
155 GPollFD *pollfd = l->data;
156
157 if (pollfd->fd != fd)
158 continue;
159
160 g_source_remove_poll((GSource *) fdsource, pollfd);
161 g_slice_free(GPollFD, pollfd);
162 fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l);
163 return;
164 }
165
166 g_error("couldn't find fd %d in list\n", fd);
167 }
168
setup_pollfds(void)169 int setup_pollfds(void)
170 {
171 size_t numfds;
172 size_t i;
173 struct fp_pollfd *fpfds;
174 GSource *gsource;
175
176 gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource));
177 fdsource = (struct fdsource *) gsource;
178 fdsource->pollfds = NULL;
179
180 numfds = fp_get_pollfds(&fpfds);
181 if (numfds < 0) {
182 if (fpfds)
183 free(fpfds);
184 return (int) numfds;
185 } else if (numfds > 0) {
186 for (i = 0; i < numfds; i++) {
187 struct fp_pollfd *fpfd = &fpfds[i];
188 pollfd_add(fpfd->fd, fpfd->events);
189 }
190 }
191
192 free(fpfds);
193 fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb);
194 g_source_attach(gsource, NULL);
195 return 0;
196 }
197