GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/virtual-device-listener.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 103 124 83.1%
Functions: 14 15 93.3%
Branches: 47 85 55.3%

Line Branch Exec Source
1 /*
2 * Socket utilities for "simple" device debugging
3 *
4 * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
5 * Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #define FP_COMPONENT "virtual_device_connection"
23
24 #include "fpi-log.h"
25
26 #include <glib/gstdio.h>
27 #include <gio/gunixsocketaddress.h>
28
29 #include "virtual-device-private.h"
30
31 struct _FpiDeviceVirtualListener
32 {
33 GSocketListener parent_instance;
34
35 GSocketConnection *connection;
36 GCancellable *cancellable;
37 guint cancellable_id;
38
39 FpiDeviceVirtualListenerConnectionCb ready_cb;
40 gpointer ready_cb_data;
41
42 gint socket_fd;
43 gint client_fd;
44 };
45
46
4/5
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1296 times.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 93 times.
✗ Branch 4 not taken.
3150 G_DEFINE_TYPE (FpiDeviceVirtualListener, fpi_device_virtual_listener, G_TYPE_SOCKET_LISTENER)
47
48 static void start_listen (FpiDeviceVirtualListener *self);
49
50 FpiDeviceVirtualListener *
51 114 fpi_device_virtual_listener_new (void)
52 {
53 114 return g_object_new (fpi_device_virtual_listener_get_type (), NULL);
54 }
55
56 static void
57 39 fpi_device_virtual_listener_dispose (GObject *object)
58 {
59 39 FpiDeviceVirtualListener *self = FPI_DEVICE_VIRTUAL_LISTENER (object);
60
61
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (self->cancellable_id)
62 {
63 39 g_cancellable_disconnect (self->cancellable, self->cancellable_id);
64 39 self->cancellable_id = 0;
65 }
66
67 39 g_cancellable_cancel (self->cancellable);
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 g_clear_object (&self->cancellable);
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 g_clear_object (&self->connection);
70
71 39 self->ready_cb = NULL;
72
73 39 G_OBJECT_CLASS (fpi_device_virtual_listener_parent_class)->dispose (object);
74 39 }
75
76 static void
77 93 fpi_device_virtual_listener_class_init (FpiDeviceVirtualListenerClass *klass)
78 {
79 93 GObjectClass *object_class = G_OBJECT_CLASS (klass);
80
81 93 object_class->dispose = fpi_device_virtual_listener_dispose;
82 }
83
84 static void
85 114 fpi_device_virtual_listener_init (FpiDeviceVirtualListener *self)
86 {
87 114 }
88
89 static void
90 510 new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
91 {
92 510 g_autoptr(GError) error = NULL;
93 510 FpiDeviceVirtualListener *self = user_data;
94 510 GSocketConnection *connection;
95
96 510 connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object),
97 res,
98 NULL,
99 &error);
100
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 471 times.
510 if (!connection)
101 {
102
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
39 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
103 return;
104
105 g_warning ("Error accepting a new connection: %s", error->message);
106 start_listen (self);
107 return;
108 }
109
110 /* Always allow further connections.
111 * If we get a new one, we generally just close the old connection. */
112 471 start_listen (self);
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 471 times.
471 if (self->connection)
114 {
115 g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
116 g_clear_object (&self->connection);
117 }
118
119 471 self->connection = connection;
120 471 fp_dbg ("Got a new connection!");
121
122
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 471 times.
471 self->ready_cb (self, self->ready_cb_data);
123 }
124
125 static void
126 585 start_listen (FpiDeviceVirtualListener *self)
127 {
128 585 g_socket_listener_accept_async (G_SOCKET_LISTENER (self),
129 self->cancellable,
130 new_connection_cb,
131 self);
132 585 }
133
134 static void
135 114 on_cancelled (GCancellable *cancellable,
136 FpiDeviceVirtualListener *self)
137 {
138 114 fpi_device_virtual_listener_connection_close (self);
139 114 g_socket_listener_close (G_SOCKET_LISTENER (self));
140
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 g_clear_object (&self->cancellable);
141 114 self->ready_cb = NULL;
142 114 }
143
144 gboolean
145 114 fpi_device_virtual_listener_start (FpiDeviceVirtualListener *self,
146 const char *address,
147 GCancellable *cancellable,
148 FpiDeviceVirtualListenerConnectionCb cb,
149 gpointer user_data,
150 GError **error)
151 {
152 228 g_autoptr(GSocketAddress) addr = NULL;
153 114 G_DEBUG_HERE ();
154
155
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 g_return_val_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 g_return_val_if_fail (cb != NULL, FALSE);
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 g_return_val_if_fail (self->ready_cb == NULL, FALSE);
158
159 114 self->client_fd = -1;
160
161 114 g_socket_listener_set_backlog (G_SOCKET_LISTENER (self), 1);
162
163 /* Remove any left over socket. */
164 114 g_unlink (address);
165
166 114 addr = g_unix_socket_address_new (address);
167
168
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
114 if (!g_socket_listener_add_address (G_SOCKET_LISTENER (self),
169 addr,
170 G_SOCKET_TYPE_STREAM,
171 G_SOCKET_PROTOCOL_DEFAULT,
172 NULL,
173 NULL,
174 error))
175 {
176 g_warning ("Could not listen on unix socket: %s", (*error)->message);
177 return FALSE;
178 }
179
180 114 self->ready_cb = cb;
181 114 self->ready_cb_data = user_data;
182
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 self->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
183
184
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 if (self->cancellable)
185 114 self->cancellable_id = g_cancellable_connect (self->cancellable,
186 G_CALLBACK (on_cancelled), self, NULL);
187
188 114 start_listen (self);
189
190 114 return TRUE;
191 }
192
193 gboolean
194 581 fpi_device_virtual_listener_connection_close (FpiDeviceVirtualListener *self)
195 {
196
1/2
✓ Branch 1 taken 581 times.
✗ Branch 2 not taken.
581 g_return_val_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self), FALSE);
197
198
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 471 times.
581 if (!self->connection)
199 return FALSE;
200
201 471 g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
202
1/2
✓ Branch 0 taken 471 times.
✗ Branch 1 not taken.
471 g_clear_object (&self->connection);
203
204 return TRUE;
205 }
206
207 static void
208 575 on_stream_read_cb (GObject *source_object,
209 GAsyncResult *res,
210 gpointer user_data)
211 {
212 575 g_autoptr(GError) error = NULL;
213
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 557 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 14 times.
575 g_autoptr(GTask) task = user_data;
214 575 FpiDeviceVirtualListener *self = g_task_get_source_object (task);
215 575 gboolean all;
216 575 gboolean success;
217 575 gsize bytes;
218
219 575 all = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "all"));
220
221
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 467 times.
575 if (all)
222 {
223 108 success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
224 }
225 else
226 {
227 467 gssize sbytes;
228
229 467 sbytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
230 467 bytes = sbytes;
231 467 success = (sbytes >= 0);
232 }
233
234
2/2
✓ Branch 1 taken 571 times.
✓ Branch 2 taken 4 times.
575 if (g_task_return_error_if_cancelled (task))
235 return;
236
237 /* If we are cancelled, just return immediately. */
238
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 571 times.
571 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
239 {
240 g_task_return_int (task, 0);
241 return;
242 }
243
244 /* If this error is for an old connection (that should be closed already),
245 * then just give up immediately with a CLOSED error.
246 */
247
2/4
✓ Branch 0 taken 571 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 571 times.
1142 if (self->connection &&
248 571 g_io_stream_get_input_stream (G_IO_STREAM (self->connection)) != G_INPUT_STREAM (source_object))
249 {
250 g_task_return_new_error (task,
251 G_IO_ERROR,
252 G_IO_ERROR_CLOSED,
253 "Error on old connection, ignoring.");
254 return;
255 }
256
257
3/4
✓ Branch 0 taken 557 times.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 557 times.
571 if (!success || bytes == 0)
258 {
259 /* We accept it if someone tries to read twice and just return that error. */
260
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
14 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
261 {
262 if (self->connection)
263 {
264 g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
265 g_clear_object (&self->connection);
266 }
267 }
268
269
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (error)
270 {
271 14 g_task_return_error (task, g_steal_pointer (&error));
272 14 return;
273 }
274 else
275 {
276 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
277 "Got empty data");
278 return;
279 }
280 }
281
282
1/2
✓ Branch 1 taken 557 times.
✗ Branch 2 not taken.
557 g_task_return_int (task, bytes);
283 }
284
285 void
286 580 fpi_device_virtual_listener_read (FpiDeviceVirtualListener *self,
287 gboolean all,
288 void *buffer,
289 gsize count,
290 GAsyncReadyCallback callback,
291 gpointer user_data)
292 {
293 1160 g_autoptr(GTask) task = NULL;
294 580 GInputStream *stream;
295
296
1/2
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
580 g_return_if_fail (FPI_IS_DEVICE_VIRTUAL_LISTENER (self));
297
298 580 task = g_task_new (self, self->cancellable, callback, user_data);
299 580 g_object_set_data (G_OBJECT (task), "all", GINT_TO_POINTER (all));
300
301
3/4
✓ Branch 0 taken 575 times.
✓ Branch 1 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 575 times.
580 if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
302 {
303 5 g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
304 "Listener not connected to any stream");
305
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 return;
306 }
307
308 575 stream = g_io_stream_get_input_stream (G_IO_STREAM (self->connection));
309
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 467 times.
575 if (all)
310 {
311 108 g_input_stream_read_all_async (stream, buffer, count,
312 G_PRIORITY_DEFAULT,
313 self->cancellable,
314 on_stream_read_cb,
315 g_steal_pointer (&task));
316 }
317 else
318 {
319 467 g_input_stream_read_async (stream, buffer, count,
320 G_PRIORITY_DEFAULT,
321 self->cancellable,
322 on_stream_read_cb,
323 g_steal_pointer (&task));
324 }
325 }
326
327 gsize
328 580 fpi_device_virtual_listener_read_finish (FpiDeviceVirtualListener *self,
329 GAsyncResult *result,
330 GError **error)
331 {
332
1/2
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
580 g_return_val_if_fail (g_task_is_valid (result, self), 0);
333
334 580 return g_task_propagate_int (G_TASK (result), error);
335 }
336
337 gboolean
338 fpi_device_virtual_listener_write_sync (FpiDeviceVirtualListener *self,
339 const char *buffer,
340 gsize count,
341 GError **error)
342 {
343 if (!self->connection || g_io_stream_is_closed (G_IO_STREAM (self->connection)))
344 {
345 g_set_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED,
346 "Listener not connected to any stream");
347 return FALSE;
348 }
349
350 return g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (self->connection)),
351 buffer,
352 count,
353 NULL,
354 self->cancellable,
355 error);
356 }
357