Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-lan-channel-service"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <gio/gunixinputstream.h>
10 : : #include <valent.h>
11 : :
12 : : #include "valent-lan-channel.h"
13 : : #include "valent-lan-channel-service.h"
14 : : #include "valent-lan-dnssd.h"
15 : : #include "valent-lan-utils.h"
16 : :
17 : : #define HANDSHAKE_TIMEOUT_MS (1000)
18 : : #define IDENTITY_BUFFER_MAX (8192)
19 : :
20 : : #if VALENT_SANITIZE_ADDRESS
21 : : #undef HANDSHAKE_TIMEOUT_MS
22 : : #define HANDSHAKE_TIMEOUT_MS (10000)
23 : : #endif
24 : :
25 : : struct _ValentLanChannelService
26 : : {
27 : : ValentChannelService parent_instance;
28 : :
29 : : GNetworkMonitor *monitor;
30 : : gboolean network_available;
31 : :
32 : : /* Service */
33 : : uint16_t port;
34 : : uint16_t tcp_port;
35 : : char *broadcast_address;
36 : : GListModel *dnssd;
37 : : GSocketService *listener;
38 : : GSocket *udp_socket4;
39 : : GSocket *udp_socket6;
40 : : GHashTable *channels;
41 : : };
42 : :
43 : : static void g_initable_iface_init (GInitableIface *iface);
44 : :
45 [ + + + - ]: 38 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentLanChannelService, valent_lan_channel_service, VALENT_TYPE_CHANNEL_SERVICE,
46 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, g_initable_iface_init))
47 : :
48 : : typedef enum {
49 : : PROP_BROADCAST_ADDRESS = 1,
50 : : PROP_PORT,
51 : : } ValentLanChannelServiceProperty;
52 : :
53 : : static GParamSpec *properties[PROP_PORT + 1] = { NULL, };
54 : :
55 : : static void
56 : 0 : on_network_changed (GNetworkMonitor *monitor,
57 : : gboolean network_available,
58 : : ValentLanChannelService *self)
59 : : {
60 [ # # ]: 0 : if (self->network_available == network_available)
61 : : return;
62 : :
63 : 0 : self->network_available = network_available;
64 [ # # ]: 0 : if (self->network_available)
65 : : {
66 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
67 : : VALENT_PLUGIN_STATE_ACTIVE,
68 : : NULL);
69 : 0 : valent_channel_service_identify (VALENT_CHANNEL_SERVICE (self), NULL);
70 : : }
71 : : else
72 : : {
73 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
74 : : VALENT_PLUGIN_STATE_INACTIVE,
75 : : NULL);
76 : : }
77 : : }
78 : :
79 : : static void
80 : 0 : on_channel_destroyed (ValentLanChannelService *self,
81 : : ValentLanChannel *channel)
82 : : {
83 : 0 : g_autoptr (GTlsCertificate) certificate = NULL;
84 : 0 : const char *device_id = NULL;
85 : :
86 [ # # ]: 0 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
87 [ # # ]: 0 : g_assert (VALENT_IS_LAN_CHANNEL (channel));
88 : :
89 : 0 : certificate = valent_channel_ref_certificate (VALENT_CHANNEL (channel));
90 : 0 : device_id = valent_certificate_get_common_name (certificate);
91 [ # # ]: 0 : g_hash_table_remove (self->channels, device_id);
92 : 0 : }
93 : :
94 : : /*
95 : : * Connection Handshake
96 : : *
97 : : * The handshake begins after the discovered device receives an identity packet.
98 : : * In protocol v7 this simply means negotiating a TLS connection, while
99 : : * protocol v8 requires re-exchanging identity packets over the encrypted
100 : : * connection.
101 : : */
102 : : typedef enum
103 : : {
104 : : HANDSHAKE_ENCRYPTED = (1 << 0),
105 : : HANDSHAKE_IDENTITY_READ = (1 << 1),
106 : : HANDSHAKE_IDENTITY_SENT = (1 << 2),
107 : : HANDSHAKE_FAILED = (1 << 3),
108 : : HANDSHAKE_COMPLETE = (HANDSHAKE_ENCRYPTED |
109 : : HANDSHAKE_IDENTITY_READ |
110 : : HANDSHAKE_IDENTITY_SENT),
111 : : } HandshakeFlags;
112 : :
113 : : typedef struct
114 : : {
115 : : GIOStream *connection;
116 : : JsonNode *peer_identity;
117 : : char *host;
118 : : uint16_t port;
119 : : int64_t protocol_version;
120 : : HandshakeFlags flags;
121 : : GCancellable *cancellable;
122 : : unsigned long cancellable_id;
123 : : GCancellable *task_cancellable;
124 : : GSource *timeout;
125 : : } HandshakeData;
126 : :
127 : : static void
128 : 0 : handshake_cancelled_cb (GCancellable *cancellable,
129 : : gpointer data)
130 : : {
131 [ # # # # : 0 : g_assert (G_IS_CANCELLABLE (data));
# # # # ]
132 : :
133 : 0 : g_cancellable_cancel ((GCancellable *)data);
134 : 0 : }
135 : :
136 : : static gboolean
137 : 0 : handshake_timeout_cb (gpointer data)
138 : : {
139 [ # # # # : 0 : g_assert (G_IS_CANCELLABLE (data));
# # # # ]
140 : :
141 : 0 : g_cancellable_cancel ((GCancellable *)data);
142 : :
143 : 0 : return G_SOURCE_REMOVE;
144 : : }
145 : :
146 : : static HandshakeData *
147 : 3 : handshake_data_new (GCancellable *cancellable)
148 : : {
149 : 3 : HandshakeData *ret = NULL;
150 : 6 : g_autoptr (GMainContext) context = NULL;
151 : :
152 [ + - + - : 3 : g_assert (G_IS_CANCELLABLE (cancellable));
- + - - ]
153 : :
154 : 3 : context = g_main_context_ref_thread_default ();
155 : :
156 : 3 : ret = g_new0 (HandshakeData, 1);
157 : 3 : ret->task_cancellable = g_cancellable_new ();
158 : :
159 : 3 : ret->timeout = g_timeout_source_new (HANDSHAKE_TIMEOUT_MS);
160 : 3 : g_source_set_priority (ret->timeout, G_PRIORITY_HIGH);
161 : 3 : g_source_set_static_name (ret->timeout, "[valent-lan-plugin] handshake timeout");
162 : 3 : g_source_set_callback (ret->timeout,
163 : : handshake_timeout_cb,
164 : : g_object_ref (ret->task_cancellable),
165 : : g_object_unref);
166 : 3 : g_source_attach (ret->timeout, context);
167 : :
168 : 3 : if (cancellable != NULL)
169 : : {
170 : 3 : ret->cancellable = g_object_ref (cancellable);
171 : 3 : ret->cancellable_id = g_cancellable_connect (ret->cancellable,
172 : : G_CALLBACK (handshake_cancelled_cb),
173 : : g_object_ref (ret->task_cancellable),
174 : : g_object_unref);
175 : : }
176 : :
177 [ + - ]: 3 : return ret;
178 : : }
179 : :
180 : : static void
181 : 3 : handshake_data_free (gpointer user_data)
182 : : {
183 : 3 : HandshakeData *data = (HandshakeData *)user_data;
184 : :
185 [ + - ]: 3 : if (data->cancellable != NULL)
186 : : {
187 : 3 : g_cancellable_disconnect (data->cancellable, data->cancellable_id);
188 [ + - ]: 3 : g_clear_object (&data->cancellable);
189 : : }
190 : :
191 [ + - ]: 3 : if (data->timeout != NULL)
192 : : {
193 : 3 : g_source_destroy (data->timeout);
194 [ + - ]: 3 : g_clear_pointer (&data->timeout, g_source_unref);
195 : : }
196 : :
197 [ + - ]: 3 : g_clear_object (&data->connection);
198 [ + - ]: 3 : g_clear_pointer (&data->peer_identity, json_node_unref);
199 [ + - ]: 3 : g_clear_pointer (&data->host, g_free);
200 [ + - ]: 3 : g_clear_object (&data->task_cancellable);
201 : 3 : g_free (data);
202 : 3 : }
203 : :
204 : : static void
205 : 3 : handshake_data_cb (GObject *object,
206 : : GAsyncResult *result,
207 : : gpointer user_data)
208 : : {
209 : 3 : HandshakeData *data = g_task_get_task_data (G_TASK (result));
210 : 6 : g_autoptr (GError) error = NULL;
211 : :
212 [ - + ]: 3 : if (!g_task_propagate_boolean (G_TASK (result), &error))
213 : : {
214 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
215 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
216 [ # # ]: 0 : else if (!g_cancellable_is_cancelled (data->cancellable))
217 : 0 : g_warning ("%s(): timed out waiting for peer", G_STRFUNC);
218 : : }
219 : 3 : }
220 : :
221 : : static void
222 : 3 : handshake_task_complete (GTask *task)
223 : : {
224 : 3 : ValentChannelService *service = g_task_get_source_object (task);
225 : 3 : HandshakeData *data = g_task_get_task_data (task);
226 : 6 : g_autoptr (ValentChannel) channel = NULL;
227 [ + - ]: 3 : g_autoptr (JsonNode) identity = NULL;
228 : 3 : GTlsCertificate *certificate = NULL;
229 : 3 : GTlsCertificate *peer_certificate = NULL;
230 : :
231 : 3 : identity = valent_channel_service_ref_identity (service);
232 : 3 : certificate = g_tls_connection_get_certificate (G_TLS_CONNECTION (data->connection));
233 : 3 : peer_certificate = g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (data->connection));
234 : 3 : channel = g_object_new (VALENT_TYPE_LAN_CHANNEL,
235 : : "base-stream", data->connection,
236 : : "certificate", certificate,
237 : : "identity", identity,
238 : : "peer-certificate", peer_certificate,
239 : : "peer-identity", data->peer_identity,
240 : : "host", data->host,
241 : 3 : "port", data->port,
242 : : NULL);
243 : :
244 : 3 : valent_channel_service_channel (service, channel);
245 : :
246 [ + - ]: 3 : g_task_return_boolean (task, TRUE);
247 : 3 : }
248 : :
249 : : static void
250 : 3 : handshake_read_identity_cb (GInputStream *stream,
251 : : GAsyncResult *result,
252 : : gpointer user_data)
253 : : {
254 : 6 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
255 : 3 : HandshakeData *data = g_task_get_task_data (task);
256 [ + - - - ]: 3 : g_autoptr (JsonNode) secure_identity = NULL;
257 : 3 : int64_t protocol_version;
258 : 3 : GError *error = NULL;
259 : :
260 : 3 : secure_identity = valent_packet_from_stream_finish (stream, result, &error);
261 [ - + ]: 3 : if (secure_identity == NULL)
262 : : {
263 [ # # ]: 0 : if ((data->flags & HANDSHAKE_FAILED) == 0)
264 : : {
265 : 0 : data->flags |= HANDSHAKE_FAILED;
266 : 0 : g_task_return_error (task, g_steal_pointer (&error));
267 : : }
268 : :
269 : 0 : return;
270 : : }
271 : :
272 [ - + ]: 3 : if (!valent_packet_get_int (secure_identity, "protocolVersion", &protocol_version))
273 : : {
274 : 0 : g_task_return_new_error (task,
275 : : VALENT_PACKET_ERROR,
276 : : VALENT_PACKET_ERROR_MISSING_FIELD,
277 : : "expected \"protocolVersion\" field holding an integer");
278 : 0 : return;
279 : : }
280 : :
281 [ - + ]: 3 : if (data->protocol_version != protocol_version)
282 : : {
283 : 0 : g_task_return_new_error (task,
284 : : G_IO_ERROR,
285 : : G_IO_ERROR_NOT_SUPPORTED,
286 : : "Unexpected protocol version \"%u\"; "
287 : : "handshake began with version \"%u\"",
288 : 0 : (uint8_t)protocol_version,
289 : 0 : (uint8_t)data->protocol_version);
290 : 0 : return;
291 : : }
292 : :
293 [ + - ]: 3 : g_clear_pointer (&data->peer_identity, json_node_unref);
294 [ + - ]: 3 : data->peer_identity = g_steal_pointer (&secure_identity);
295 : :
296 : 3 : data->flags |= HANDSHAKE_IDENTITY_READ;
297 [ + - ]: 3 : if (data->flags == HANDSHAKE_COMPLETE)
298 : 3 : handshake_task_complete (task);
299 : : }
300 : :
301 : : static void
302 : 3 : handshake_write_identity_cb (GOutputStream *stream,
303 : : GAsyncResult *result,
304 : : gpointer user_data)
305 : : {
306 : 6 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
307 : 3 : HandshakeData *data = g_task_get_task_data (task);
308 : 3 : GError *error = NULL;
309 : :
310 [ - + ]: 3 : if (!valent_packet_to_stream_finish (stream, result, &error))
311 : : {
312 [ # # ]: 0 : if ((data->flags & HANDSHAKE_FAILED) == 0)
313 : : {
314 : 0 : data->flags |= HANDSHAKE_FAILED;
315 : 0 : g_task_return_error (task, g_steal_pointer (&error));
316 : : }
317 : :
318 [ # # ]: 0 : return;
319 : : }
320 : :
321 : 3 : data->flags |= HANDSHAKE_IDENTITY_SENT;
322 [ - + ]: 3 : if (data->flags == HANDSHAKE_COMPLETE)
323 : 0 : handshake_task_complete (task);
324 : : }
325 : :
326 : : static void
327 : 3 : valent_lan_connection_handshake_cb (GSocketConnection *connection,
328 : : GAsyncResult *result,
329 : : gpointer user_data)
330 : : {
331 : 6 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
332 : 3 : ValentChannelService *service = g_task_get_source_object (task);
333 : 3 : HandshakeData *data = g_task_get_task_data (task);
334 : 3 : GCancellable *cancellable = g_task_get_cancellable (task);
335 [ + - - - ]: 3 : g_autoptr (GIOStream) ret = NULL;
336 [ + - ]: 3 : g_autoptr (JsonNode) identity = NULL;
337 : 3 : GError *error = NULL;
338 : :
339 : 3 : ret = valent_lan_connection_handshake_finish (connection, result, &error);
340 [ - + ]: 3 : if (ret == NULL)
341 : : {
342 : 0 : g_task_return_error (task, g_steal_pointer (&error));
343 : 0 : return;
344 : : }
345 : :
346 [ + - ]: 3 : g_clear_object (&data->connection);
347 : 3 : data->connection = g_steal_pointer (&ret);
348 : 3 : data->flags |= HANDSHAKE_ENCRYPTED;
349 : :
350 [ - + ]: 3 : if (!valent_packet_get_int (data->peer_identity,
351 : : "protocolVersion",
352 : : &data->protocol_version))
353 : : {
354 : 0 : g_task_return_new_error (task,
355 : : VALENT_PACKET_ERROR,
356 : : VALENT_PACKET_ERROR_MISSING_FIELD,
357 : : "expected \"protocolVersion\" field holding an integer");
358 : 0 : return;
359 : : }
360 : :
361 [ - + ]: 3 : if (data->protocol_version > VALENT_NETWORK_PROTOCOL_MAX ||
362 : : data->protocol_version < VALENT_NETWORK_PROTOCOL_MIN)
363 : : {
364 : 0 : g_task_return_new_error (task,
365 : : G_IO_ERROR,
366 : : G_IO_ERROR_NOT_SUPPORTED,
367 : : "Unsupported protocol version \"%u\"",
368 : 0 : (uint8_t)data->protocol_version);
369 : 0 : return;
370 : : }
371 : :
372 [ + - ]: 3 : if (data->protocol_version >= VALENT_NETWORK_PROTOCOL_V8)
373 : : {
374 : 3 : identity = valent_channel_service_ref_identity (service);
375 : 3 : valent_packet_to_stream_async (g_io_stream_get_output_stream (data->connection),
376 : : identity,
377 : : cancellable,
378 : : (GAsyncReadyCallback)handshake_write_identity_cb,
379 : : g_object_ref (task));
380 : 3 : valent_packet_from_stream_async (g_io_stream_get_input_stream (data->connection),
381 : : IDENTITY_BUFFER_MAX,
382 : : cancellable,
383 : : (GAsyncReadyCallback)handshake_read_identity_cb,
384 : : g_object_ref (task));
385 : : }
386 : : else
387 : : {
388 : 0 : data->flags = HANDSHAKE_COMPLETE;
389 : 0 : handshake_task_complete (task);
390 : : }
391 : : }
392 : :
393 : : static void
394 : 1 : valent_packet_from_stream_cb (GInputStream *stream,
395 : : GAsyncResult *result,
396 : : gpointer user_data)
397 : : {
398 : 2 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
399 : 1 : ValentChannelService *service = g_task_get_source_object (task);
400 : 1 : HandshakeData *data = g_task_get_task_data (task);
401 : 1 : GCancellable *cancellable = g_task_get_cancellable (task);
402 [ + - - - ]: 1 : g_autoptr (GTlsCertificate) certificate = NULL;
403 : 1 : const char *device_id = NULL;
404 [ + - - - ]: 1 : g_autoptr (GIOStream) ret = NULL;
405 : 1 : GError *error = NULL;
406 : :
407 : 1 : data->peer_identity = valent_packet_from_stream_finish (stream, result, &error);
408 [ - + ]: 1 : if (data->peer_identity == NULL)
409 : : {
410 : 0 : g_task_return_error (task, g_steal_pointer (&error));
411 : 0 : return;
412 : : }
413 : :
414 [ - + ]: 1 : if (!valent_packet_get_string (data->peer_identity, "deviceId", &device_id))
415 : : {
416 : 0 : g_task_return_new_error (task,
417 : : VALENT_PACKET_ERROR,
418 : : VALENT_PACKET_ERROR_MISSING_FIELD,
419 : : "expected \"deviceId\" field holding a string");
420 : 0 : return;
421 : : }
422 : :
423 [ - + ]: 1 : if (!valent_device_validate_id (device_id))
424 : : {
425 : 0 : g_task_return_new_error (task,
426 : : G_IO_ERROR,
427 : : G_IO_ERROR_NOT_SUPPORTED,
428 : : "Invalid device ID \"%s\"",
429 : : device_id);
430 : 0 : return;
431 : : }
432 : :
433 : 1 : VALENT_JSON (data->peer_identity, data->host);
434 : :
435 : : /* NOTE: When negotiating the primary connection, a KDE Connect device
436 : : * acts as the TLS client when accepting TCP connections
437 : : */
438 : 1 : certificate = valent_channel_service_ref_certificate (service);
439 [ + - ]: 1 : valent_lan_connection_handshake_async (G_SOCKET_CONNECTION (data->connection),
440 : : certificate,
441 : : NULL, /* trusted */
442 : : TRUE, /* is_client */
443 : : cancellable,
444 : : (GAsyncReadyCallback)valent_lan_connection_handshake_cb,
445 : : g_object_ref (task));
446 : : }
447 : :
448 : : static void
449 : 2 : valent_packet_to_stream_cb (GOutputStream *stream,
450 : : GAsyncResult *result,
451 : : gpointer user_data)
452 : : {
453 : 4 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
454 : 2 : ValentChannelService *service = g_task_get_source_object (task);
455 : 2 : HandshakeData *data = g_task_get_task_data (task);
456 : 2 : GCancellable *cancellable = g_task_get_cancellable (task);
457 [ - - + - ]: 2 : g_autoptr (GTlsCertificate) certificate = NULL;
458 : 2 : GError *error = NULL;
459 : :
460 [ - + ]: 2 : if (!valent_packet_to_stream_finish (stream, result, &error))
461 : : {
462 : 0 : g_task_return_error (task, g_steal_pointer (&error));
463 [ # # ]: 0 : return;
464 : : }
465 : :
466 : : /* NOTE: When negotiating the primary connection, a KDE Connect device
467 : : * acts as the TLS server when opening TCP connections
468 : : */
469 : 2 : certificate = valent_channel_service_ref_certificate (service);
470 [ + - ]: 2 : valent_lan_connection_handshake_async (G_SOCKET_CONNECTION (data->connection),
471 : : certificate,
472 : : NULL, /* trusted */
473 : : FALSE, /* is_client */
474 : : cancellable,
475 : : (GAsyncReadyCallback)valent_lan_connection_handshake_cb,
476 : : g_object_ref (task));
477 : : }
478 : :
479 : : static void
480 : 2 : g_socket_client_connect_to_host_cb (GSocketClient *client,
481 : : GAsyncResult *result,
482 : : gpointer user_data)
483 : : {
484 : 4 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
485 : 2 : ValentChannelService *service = g_task_get_source_object (task);
486 : 2 : HandshakeData *data = g_task_get_task_data (task);
487 : 2 : GCancellable *cancellable = g_task_get_cancellable (task);
488 [ - - + - ]: 2 : g_autoptr (GSocketConnection) connection = NULL;
489 [ - - ]: 2 : g_autoptr (JsonNode) identity = NULL;
490 : 2 : GError *error = NULL;
491 : :
492 : 2 : connection = g_socket_client_connect_to_host_finish (client, result, &error);
493 [ - + ]: 2 : if (connection == NULL)
494 : : {
495 : 0 : g_task_return_error (task, g_steal_pointer (&error));
496 [ # # ]: 0 : return;
497 : : }
498 : :
499 : 2 : g_set_object (&data->connection, G_IO_STREAM (connection));
500 : :
501 : : /* The outgoing connection is in response to the remote device's broadcast,
502 : : * so the local device must send its identity before TLS negotiation.
503 : : */
504 : 2 : identity = valent_channel_service_ref_identity (service);
505 [ + - ]: 2 : valent_packet_to_stream_async (g_io_stream_get_output_stream (data->connection),
506 : : identity,
507 : : cancellable,
508 : : (GAsyncReadyCallback)valent_packet_to_stream_cb,
509 : : g_object_ref (task));
510 : : }
511 : :
512 : : /*
513 : : * Incoming Connections
514 : : */
515 : : static gboolean
516 : 1 : on_incoming_connection (ValentChannelService *service,
517 : : GSocketConnection *connection,
518 : : GCancellable *cancellable,
519 : : GSocketService *listener)
520 : : {
521 : 2 : g_autoptr (GTask) task = NULL;
522 : 1 : HandshakeData *data = NULL;
523 [ + - ]: 1 : g_autoptr (GSocketAddress) s_addr = NULL;
524 : 1 : GInetAddress *i_addr = NULL;
525 : :
526 [ - + ]: 1 : g_assert (VALENT_IS_CHANNEL_SERVICE (service));
527 : :
528 : 1 : s_addr = g_socket_connection_get_remote_address (connection, NULL);
529 : 1 : i_addr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (s_addr));
530 : :
531 : 1 : data = handshake_data_new (cancellable);
532 : 1 : data->connection = g_object_ref (G_IO_STREAM (connection));
533 : 1 : data->host = g_inet_address_to_string (i_addr);
534 : 1 : data->port = VALENT_LAN_PROTOCOL_PORT;
535 : :
536 : 1 : task = g_task_new (service, data->task_cancellable, handshake_data_cb, NULL);
537 [ + - ]: 1 : g_task_set_source_tag (task, on_incoming_connection);
538 : 1 : g_task_set_task_data (task, data, handshake_data_free);
539 : :
540 : : /* The incoming connection is in response to the local device's broadcast,
541 : : * so the remote device must send its identity before TLS negotiation.
542 : : */
543 : 1 : valent_packet_from_stream_async (g_io_stream_get_input_stream (data->connection),
544 : : IDENTITY_BUFFER_MAX,
545 : : data->task_cancellable,
546 : : (GAsyncReadyCallback)valent_packet_from_stream_cb,
547 : : g_object_ref (task));
548 : :
549 [ + - ]: 1 : return TRUE;
550 : : }
551 : :
552 : : /*
553 : : * Outgoing Connections
554 : : */
555 : : static gboolean
556 : 6 : valent_lan_channel_service_socket_recv (GSocket *socket,
557 : : GIOCondition condition,
558 : : gpointer user_data)
559 : : {
560 : 6 : ValentChannelService *service = VALENT_CHANNEL_SERVICE (user_data);
561 : 12 : g_autoptr (GCancellable) cancellable = NULL;
562 [ + + ]: 6 : g_autoptr (GError) error = NULL;
563 : 6 : gssize read = 0;
564 : 6 : char buffer[IDENTITY_BUFFER_MAX + 1] = { 0, };
565 [ - + ]: 6 : g_autoptr (GSocketAddress) incoming = NULL;
566 [ + + ]: 6 : g_autoptr (GSocketClient) client = NULL;
567 : 6 : GInetAddress *addr = NULL;
568 [ + + ]: 6 : g_autoptr (JsonNode) peer_identity = NULL;
569 : 6 : const char *device_id;
570 [ + + ]: 6 : g_autofree char *local_id = NULL;
571 : 6 : g_autoptr (GTask) task = NULL;
572 : 6 : HandshakeData *data = NULL;
573 [ + + ]: 6 : g_autoptr (GError) warning = NULL;
574 : 6 : int64_t port = VALENT_LAN_PROTOCOL_PORT;
575 : :
576 : 6 : VALENT_ENTRY;
577 : :
578 [ + - + - : 6 : g_assert (G_IS_SOCKET (socket));
- + - - ]
579 [ + - ]: 6 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (user_data));
580 : :
581 [ + + ]: 6 : if (condition != G_IO_IN)
582 : 3 : VALENT_RETURN (G_SOURCE_REMOVE);
583 : :
584 : : /* Read the message data and extract the remote address
585 : : */
586 : 3 : cancellable = valent_object_ref_cancellable (VALENT_OBJECT (service));
587 : 3 : read = g_socket_receive_from (socket,
588 : : &incoming,
589 : : buffer,
590 : : IDENTITY_BUFFER_MAX,
591 : : cancellable,
592 : : &error);
593 : :
594 [ - + ]: 3 : if (read == -1)
595 : : {
596 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
597 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
598 : :
599 : 0 : VALENT_RETURN (G_SOURCE_REMOVE);
600 : : }
601 : :
602 [ - + ]: 3 : if (read == 0)
603 : : {
604 : 0 : g_warning ("%s(): Socket is closed", G_STRFUNC);
605 : 0 : VALENT_RETURN (G_SOURCE_REMOVE);
606 : : }
607 : :
608 : : /* Validate the message as a KDE Connect packet
609 : : */
610 : 3 : peer_identity = valent_packet_deserialize (buffer, &warning);
611 [ - + ]: 3 : if (peer_identity == NULL)
612 : : {
613 : 0 : g_warning ("%s(): failed to parse peer-identity: %s",
614 : : G_STRFUNC,
615 : : warning->message);
616 : 0 : VALENT_RETURN (G_SOURCE_CONTINUE);
617 : : }
618 : :
619 : : /* Ignore broadcasts without a deviceId or with an invalid deviceId
620 : : */
621 [ - + ]: 3 : if (!valent_packet_get_string (peer_identity, "deviceId", &device_id))
622 : : {
623 : 0 : g_debug ("%s(): expected \"deviceId\" field holding a string",
624 : : G_STRFUNC);
625 : 0 : VALENT_RETURN (G_SOURCE_CONTINUE);
626 : : }
627 : :
628 [ - + ]: 3 : if (!valent_device_validate_id (device_id))
629 : : {
630 : 0 : g_warning ("%s(): invalid device ID \"%s\"", G_STRFUNC, device_id);
631 : 0 : VALENT_RETURN (G_SOURCE_CONTINUE);
632 : : }
633 : :
634 : : /* Silently ignore our own broadcasts
635 : : */
636 : 3 : local_id = valent_channel_service_dup_id (service);
637 [ + + ]: 3 : if (g_strcmp0 (device_id, local_id) == 0)
638 : 2 : VALENT_RETURN (G_SOURCE_CONTINUE);
639 : :
640 : 2 : VALENT_JSON (peer_identity, device_id);
641 : :
642 : : /* Get the remote address and port
643 : : */
644 : 2 : addr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (incoming));
645 [ + - ]: 2 : if (!valent_packet_get_int (peer_identity, "tcpPort", &port) ||
646 [ - + ]: 2 : (port < VALENT_LAN_PROTOCOL_PORT_MIN || port > VALENT_LAN_PROTOCOL_PORT_MAX))
647 : : {
648 : 0 : g_warning ("%s(): expected \"tcpPort\" field holding a uint16 between %u-%u",
649 : : G_STRFUNC,
650 : : VALENT_LAN_PROTOCOL_PORT_MIN,
651 : : VALENT_LAN_PROTOCOL_PORT_MAX);
652 : 0 : VALENT_RETURN (G_SOURCE_CONTINUE);
653 : : }
654 : :
655 : 2 : data = handshake_data_new (cancellable);
656 : 2 : data->peer_identity = json_node_ref (peer_identity);
657 : 2 : data->host = g_inet_address_to_string (addr);
658 : 2 : data->port = (uint16_t)port;
659 : :
660 : 2 : task = g_task_new (service, data->task_cancellable, handshake_data_cb, NULL);
661 [ + - ]: 2 : g_task_set_source_tag (task, valent_lan_channel_service_socket_recv);
662 : 2 : g_task_set_task_data (task, data, handshake_data_free);
663 : :
664 : : /* Open a connection to the host at the expected port
665 : : */
666 : 2 : client = g_object_new (G_TYPE_SOCKET_CLIENT,
667 : : "enable-proxy", FALSE,
668 : : NULL);
669 : 2 : g_socket_client_connect_to_host_async (client,
670 : 2 : data->host,
671 : 2 : data->port,
672 : : data->task_cancellable,
673 : : (GAsyncReadyCallback)g_socket_client_connect_to_host_cb,
674 : : g_object_ref (task));
675 : :
676 [ - + ]: 6 : VALENT_RETURN (G_SOURCE_CONTINUE);
677 : : }
678 : :
679 : : static gboolean
680 : 3 : valent_lan_channel_service_socket_send (GSocket *socket,
681 : : GIOCondition condition,
682 : : gpointer user_data)
683 : : {
684 : 3 : GSocketAddress *address = G_SOCKET_ADDRESS (user_data);
685 : 3 : GBytes *bytes = NULL;
686 : 3 : gssize written;
687 : 6 : g_autoptr (GError) error = NULL;
688 : :
689 : 3 : VALENT_ENTRY;
690 : :
691 [ + - + - : 3 : g_assert (G_IS_SOCKET (socket));
- + - - ]
692 [ + - + - : 3 : g_assert (G_IS_SOCKET_ADDRESS (address));
+ - + - ]
693 : :
694 : 3 : bytes = g_object_get_data (G_OBJECT (address), "valent-lan-broadcast");
695 : 6 : written = g_socket_send_to (socket,
696 : : address,
697 : 3 : g_bytes_get_data (bytes, NULL),
698 : : g_bytes_get_size (bytes),
699 : : NULL,
700 : : &error);
701 : :
702 : : /* Partial writes are ignored
703 : : */
704 [ - + ]: 3 : if (written == -1)
705 : : {
706 : 0 : g_autofree char *host = NULL;
707 : :
708 [ # # ]: 0 : if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
709 : 0 : VALENT_RETURN (G_SOURCE_CONTINUE);
710 : :
711 : 0 : host = g_socket_connectable_to_string (G_SOCKET_CONNECTABLE (address));
712 : 0 : g_warning ("%s(): failed to announce to \"%s\": %s",
713 : : G_STRFUNC, host, error->message);
714 : : }
715 : :
716 [ - + ]: 3 : VALENT_RETURN (G_SOURCE_REMOVE);
717 : : }
718 : :
719 : : static gboolean
720 : 3 : valent_lan_channel_service_socket_queue (ValentLanChannelService *self,
721 : : GSocketAddress *address)
722 : : {
723 : 6 : g_autoptr (GSocket) socket = NULL;
724 : 3 : GSocketFamily family = G_SOCKET_FAMILY_INVALID;
725 : :
726 [ - + ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
727 [ + - + - : 3 : g_assert (G_IS_SOCKET_ADDRESS (address));
+ - + - ]
728 : :
729 : 3 : family = g_socket_address_get_family (address);
730 [ + - ]: 3 : g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 ||
731 : : family == G_SOCKET_FAMILY_IPV6, FALSE);
732 : :
733 [ + - + - : 6 : if ((self->udp_socket6 != NULL && family == G_SOCKET_FAMILY_IPV6) ||
+ - ]
734 : 3 : (self->udp_socket6 != NULL && g_socket_speaks_ipv4 (self->udp_socket6)))
735 : : {
736 : 3 : socket = g_object_ref (self->udp_socket6);
737 : : }
738 [ # # # # ]: 0 : else if (self->udp_socket4 != NULL && family == G_SOCKET_FAMILY_IPV4)
739 : : {
740 : 0 : socket = g_object_ref (self->udp_socket4);
741 : : }
742 : :
743 [ - + ]: 3 : if (socket != NULL)
744 : : {
745 : 3 : g_autoptr (GSource) source = NULL;
746 [ + - ]: 3 : g_autoptr (JsonNode) identity = NULL;
747 [ + - ]: 3 : g_autoptr (GBytes) identity_bytes = NULL;
748 [ + - ]: 3 : g_autoptr (GCancellable) cancellable = NULL;
749 : 3 : char *identity_json = NULL;
750 : 3 : size_t identity_len;
751 : :
752 : : /* Embed the serialized identity as private data
753 : : */
754 : 3 : identity = valent_channel_service_ref_identity (VALENT_CHANNEL_SERVICE (self));
755 : 3 : identity_json = valent_packet_serialize (identity, &identity_len);
756 : 3 : identity_bytes = g_bytes_new_take (identity_json, identity_len);
757 : 3 : g_object_set_data_full (G_OBJECT (address),
758 : : "valent-lan-broadcast",
759 : 3 : g_bytes_ref (identity_bytes),
760 : : (GDestroyNotify)g_bytes_unref);
761 : :
762 : 3 : cancellable = valent_object_ref_cancellable (VALENT_OBJECT (self));
763 : 3 : source = g_socket_create_source (socket, G_IO_OUT, cancellable);
764 : 3 : g_source_set_callback (source,
765 : : G_SOURCE_FUNC (valent_lan_channel_service_socket_send),
766 : : g_object_ref (address),
767 : : g_object_unref);
768 : 3 : g_source_attach (source, NULL);
769 : :
770 [ + - ]: 3 : return TRUE;
771 : : }
772 : :
773 : : return FALSE;
774 : : }
775 : :
776 : : static void
777 : 3 : g_socket_address_enumerator_next_cb (GObject *object,
778 : : GAsyncResult *result,
779 : : gpointer user_data)
780 : : {
781 : 3 : GSocketAddressEnumerator *iter = G_SOCKET_ADDRESS_ENUMERATOR (object);
782 : 6 : g_autoptr (ValentLanChannelService) self = g_steal_pointer (&user_data);
783 [ - - + - ]: 3 : g_autoptr (GSocketAddress) address = NULL;
784 [ - - ]: 3 : g_autoptr (GError) error = NULL;
785 : :
786 : 3 : address = g_socket_address_enumerator_next_finish (iter, result, &error);
787 [ - + ]: 3 : if (address == NULL)
788 : : {
789 [ # # # # ]: 0 : if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
790 : 0 : g_debug ("%s(): %s", G_STRFUNC, error->message);
791 : :
792 [ # # ]: 0 : return;
793 : : }
794 : :
795 [ - + ]: 3 : if (!valent_lan_channel_service_socket_queue (self, address))
796 : : {
797 : 0 : g_socket_address_enumerator_next_async (iter,
798 : : g_task_get_cancellable (G_TASK (result)),
799 : : g_socket_address_enumerator_next_cb,
800 : : g_object_ref (self));
801 : : }
802 : : }
803 : :
804 : : static void
805 : 3 : valent_lan_channel_service_socket_queue_resolve (ValentLanChannelService *self,
806 : : GSocketConnectable *host)
807 : : {
808 : 6 : g_autoptr (GSocketAddressEnumerator) iter = NULL;
809 [ + - ]: 3 : g_autoptr (GCancellable) destroy = NULL;
810 : :
811 [ - + ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
812 [ + - + - : 3 : g_assert (G_IS_SOCKET_CONNECTABLE (host));
+ - + - ]
813 : :
814 : 3 : iter = g_socket_connectable_enumerate (host);
815 : 3 : destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
816 [ + - ]: 3 : g_socket_address_enumerator_next_async (iter,
817 : : destroy,
818 : : g_socket_address_enumerator_next_cb,
819 : : g_object_ref (self));
820 : 3 : }
821 : :
822 : : /**
823 : : * valent_lan_channel_service_tcp_setup:
824 : : * @self: a `ValentLanChannelService`
825 : : * @error: (nullable): a `GError`
826 : : *
827 : : * A wrapper around g_socket_listener_add_inet_port() that can be called
828 : : * multiple times.
829 : : *
830 : : * Returns: %TRUE if successful, or %FALSE with @error set
831 : : */
832 : : static gboolean
833 : 3 : valent_lan_channel_service_tcp_setup (ValentLanChannelService *self,
834 : : GCancellable *cancellable,
835 : : GError **error)
836 : : {
837 : 6 : g_autoptr (GCancellable) destroy = NULL;
838 : :
839 [ - + ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
840 [ - + - - : 3 : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
841 [ + - + - ]: 3 : g_assert (error == NULL || *error == NULL);
842 : :
843 [ + - ]: 3 : if (g_cancellable_set_error_if_cancelled (cancellable, error))
844 : : return FALSE;
845 : :
846 : 3 : destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
847 : :
848 : : /* Pass the service as the callback data for the "incoming" signal, while
849 : : * the listener passes the object cancellable as the source object.
850 : : */
851 : 3 : self->listener = g_socket_service_new ();
852 : 3 : g_signal_connect_object (self->listener,
853 : : "incoming",
854 : : G_CALLBACK (on_incoming_connection),
855 : : self,
856 : : G_CONNECT_SWAPPED);
857 : :
858 : 3 : self->tcp_port = self->port;
859 [ - + ]: 6 : while (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (self->listener),
860 : 3 : self->tcp_port,
861 : : G_OBJECT (destroy),
862 : : error))
863 : : {
864 [ # # ]: 0 : if (self->tcp_port >= VALENT_LAN_PROTOCOL_PORT_MAX)
865 : : {
866 : 0 : g_socket_service_stop (self->listener);
867 : 0 : g_socket_listener_close (G_SOCKET_LISTENER (self->listener));
868 [ # # ]: 0 : g_clear_object (&self->listener);
869 : :
870 : 0 : return FALSE;
871 : : }
872 : :
873 : 0 : g_clear_error (error);
874 : 0 : self->tcp_port++;
875 : : }
876 : :
877 : : /* Rebuild the identity packet to populate the `tcpPort` field
878 : : */
879 : 3 : valent_channel_service_build_identity (VALENT_CHANNEL_SERVICE (self));
880 : :
881 : 3 : return TRUE;
882 : : }
883 : :
884 : : /**
885 : : * valent_lan_channel_service_udp_setup:
886 : : * @self: a `ValentLanChannelService`
887 : : * @cancellable: (nullable): a `GCancellable`
888 : : * @error: (nullable): a `GError`
889 : : *
890 : : * An analog to valent_lan_channel_service_tcp_setup() that prepares UDP sockets
891 : : * for IPv4 and IPv6, including streams for reading.
892 : : *
893 : : * Returns: %TRUE if successful, or %FALSE with @error set
894 : : */
895 : : static gboolean
896 : 3 : valent_lan_channel_service_udp_setup (ValentLanChannelService *self,
897 : : GCancellable *cancellable,
898 : : GError **error)
899 : : {
900 : 6 : g_autoptr (GCancellable) destroy = NULL;
901 : :
902 : 3 : VALENT_ENTRY;
903 : :
904 [ - + ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
905 : 3 : g_assert (cancellable == NULL || G_CANCELLABLE (cancellable));
906 [ + - + - ]: 3 : g_assert (error == NULL || *error == NULL);
907 : :
908 : 3 : destroy = valent_object_ref_cancellable (VALENT_OBJECT (self));
909 : 3 : self->udp_socket6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
910 : : G_SOCKET_TYPE_DATAGRAM,
911 : : G_SOCKET_PROTOCOL_UDP,
912 : : NULL);
913 [ - + ]: 3 : if (self->udp_socket6 != NULL)
914 : : {
915 : 6 : g_autoptr (GInetAddress) inet_address = NULL;
916 [ - - + - : 3 : g_autoptr (GSocketAddress) address = NULL;
- - ]
917 [ - - + - : 3 : g_autoptr (GSource) source = NULL;
- - ]
918 : :
919 : 3 : inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
920 : 3 : address = g_inet_socket_address_new (inet_address, self->port);
921 : :
922 [ - + ]: 3 : if (!g_socket_bind (self->udp_socket6, address, TRUE, NULL))
923 : : {
924 [ # # ]: 0 : g_clear_object (&self->udp_socket6);
925 [ # # ]: 0 : VALENT_GOTO (ipv4);
926 : : }
927 : :
928 : 3 : g_socket_set_blocking (self->udp_socket6, FALSE);
929 : 3 : g_socket_set_broadcast (self->udp_socket6, TRUE);
930 : :
931 : 3 : source = g_socket_create_source (self->udp_socket6, G_IO_IN, destroy);
932 : 3 : g_source_set_callback (source,
933 : : G_SOURCE_FUNC (valent_lan_channel_service_socket_recv),
934 : : g_object_ref (self),
935 : : g_object_unref);
936 : 3 : g_source_attach (source, NULL);
937 : :
938 : : /* If this socket also speaks IPv4, we're done
939 : : */
940 [ + - ]: 3 : if (g_socket_speaks_ipv4 (self->udp_socket6))
941 [ + - - - ]: 3 : VALENT_RETURN (TRUE);
942 : : }
943 : :
944 : 0 : ipv4:
945 : 0 : self->udp_socket4 = g_socket_new (G_SOCKET_FAMILY_IPV4,
946 : : G_SOCKET_TYPE_DATAGRAM,
947 : : G_SOCKET_PROTOCOL_UDP,
948 : : error);
949 [ # # ]: 0 : if (self->udp_socket4 != NULL)
950 : : {
951 : 0 : g_autoptr (GInetAddress) inet_address = NULL;
952 [ # # # # ]: 0 : g_autoptr (GSocketAddress) address = NULL;
953 [ # # # # ]: 0 : g_autoptr (GSource) source = NULL;
954 : :
955 : 0 : inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
956 : 0 : address = g_inet_socket_address_new (inet_address, self->port);
957 : :
958 [ # # ]: 0 : if (!g_socket_bind (self->udp_socket4, address, TRUE, error))
959 : : {
960 [ # # ]: 0 : g_clear_object (&self->udp_socket4);
961 [ # # ]: 0 : VALENT_GOTO (check);
962 : : }
963 : :
964 : 0 : g_socket_set_blocking (self->udp_socket4, FALSE);
965 : 0 : g_socket_set_broadcast (self->udp_socket4, TRUE);
966 : :
967 : 0 : source = g_socket_create_source (self->udp_socket4, G_IO_IN, destroy);
968 : 0 : g_source_set_callback (source,
969 : : G_SOURCE_FUNC (valent_lan_channel_service_socket_recv),
970 : : g_object_ref (self),
971 : : g_object_unref);
972 [ # # ]: 0 : g_source_attach (source, NULL);
973 : : }
974 : :
975 [ # # ]: 0 : check:
976 [ # # # # ]: 0 : if (self->udp_socket6 == NULL && self->udp_socket4 == NULL)
977 : 0 : VALENT_RETURN (FALSE);
978 : :
979 : 0 : g_clear_error (error);
980 [ + - ]: 3 : VALENT_RETURN (TRUE);
981 : : }
982 : :
983 : : static void
984 : 3 : on_items_changed (GListModel *list,
985 : : unsigned int position,
986 : : unsigned int removed,
987 : : unsigned int added,
988 : : ValentLanChannelService *self)
989 : : {
990 : 3 : g_autofree char *service_id = NULL;
991 : :
992 [ - + ]: 3 : if (added == 0)
993 : 0 : return;
994 : :
995 : 3 : service_id = valent_channel_service_dup_id (VALENT_CHANNEL_SERVICE (self));
996 : :
997 [ + + ]: 6 : for (unsigned int i = 0; i < added; i++)
998 : : {
999 : 3 : g_autoptr (GSocketConnectable) connectable = NULL;
1000 [ + - + - ]: 3 : g_autofree char *device_id = NULL;
1001 : :
1002 : : /* Silently ignore our own broadcasts
1003 : : */
1004 : 3 : connectable = g_list_model_get_item (list, position + i);
1005 : 3 : device_id = g_socket_connectable_to_string (connectable);
1006 [ + + ]: 3 : if (g_strcmp0 (service_id, device_id) == 0)
1007 : 1 : continue;
1008 : :
1009 [ + - ]: 2 : if (!g_hash_table_contains (self->channels, device_id))
1010 : 2 : valent_lan_channel_service_socket_queue_resolve (self, connectable);
1011 : : }
1012 : : }
1013 : :
1014 : : /*
1015 : : * ValentChannelService
1016 : : */
1017 : : static void
1018 : 6 : valent_lan_channel_service_build_identity (ValentChannelService *service)
1019 : : {
1020 : 6 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (service);
1021 : 6 : ValentChannelServiceClass *klass;
1022 : 12 : g_autoptr (JsonNode) identity = NULL;
1023 : :
1024 [ - + ]: 6 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (service));
1025 : :
1026 : : /* Chain-up */
1027 : 6 : klass = VALENT_CHANNEL_SERVICE_CLASS (valent_lan_channel_service_parent_class);
1028 : 6 : klass->build_identity (service);
1029 : :
1030 : : /* Set the tcpPort on the packet */
1031 : 6 : identity = valent_channel_service_ref_identity (service);
1032 : :
1033 [ + - ]: 6 : if (identity != NULL)
1034 : : {
1035 : 6 : JsonObject *body;
1036 : :
1037 : 6 : body = valent_packet_get_body (identity);
1038 : 6 : json_object_set_int_member (body, "tcpPort", self->tcp_port);
1039 : : }
1040 : 6 : }
1041 : :
1042 : : static void
1043 : 3 : valent_lan_channel_service_channel (ValentChannelService *service,
1044 : : ValentChannel *channel)
1045 : : {
1046 : 3 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (service);
1047 : 6 : g_autoptr (GTlsCertificate) peer_certificate = NULL;
1048 : 3 : const char *device_id = NULL;
1049 : :
1050 [ - + ]: 3 : g_assert (VALENT_IS_MAIN_THREAD ());
1051 [ + - ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
1052 [ + - ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL (channel));
1053 : :
1054 : 3 : peer_certificate = valent_channel_ref_peer_certificate (channel);
1055 : 3 : device_id = valent_certificate_get_common_name (peer_certificate);
1056 : :
1057 [ - + ]: 3 : g_hash_table_replace (self->channels,
1058 : 3 : g_strdup (device_id),
1059 : : g_object_ref (channel));
1060 [ + - ]: 3 : g_signal_connect_object (channel,
1061 : : "destroy",
1062 : : G_CALLBACK (on_channel_destroyed),
1063 : : self,
1064 : : G_CONNECT_SWAPPED);
1065 : 3 : }
1066 : :
1067 : : static void
1068 : 1 : valent_lan_channel_service_identify (ValentChannelService *service,
1069 : : const char *target)
1070 : : {
1071 : 1 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (service);
1072 : :
1073 [ - + ]: 1 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (self));
1074 : :
1075 [ + - ]: 1 : if (!self->network_available)
1076 : : return;
1077 : :
1078 [ + - ]: 1 : if (target != NULL)
1079 : : {
1080 : 1 : g_autoptr (GSocketConnectable) net = NULL;
1081 : :
1082 : 1 : net = g_network_address_parse (target, VALENT_LAN_PROTOCOL_PORT, NULL);
1083 [ - + ]: 1 : if (net == NULL)
1084 : : {
1085 : 0 : g_debug ("%s(): failed to parse \"%s\"", G_STRFUNC, target);
1086 : 0 : return;
1087 : : }
1088 : :
1089 : 1 : valent_lan_channel_service_socket_queue_resolve (self, net);
1090 : : }
1091 : : else
1092 : : {
1093 : 1 : g_autoptr (GSocketAddress) address = NULL;
1094 : 0 : unsigned int n_items;
1095 : :
1096 : : /* Identify to each DNS-SD service
1097 : : */
1098 : 0 : n_items = g_list_model_get_n_items (self->dnssd);
1099 [ # # ]: 0 : for (unsigned int i = 0; i < n_items; i++)
1100 : : {
1101 : 0 : g_autoptr (GSocketConnectable) item = NULL;
1102 : :
1103 : 0 : item = g_list_model_get_item (self->dnssd, i);
1104 [ # # ]: 0 : valent_lan_channel_service_socket_queue_resolve (self, item);
1105 : : }
1106 : :
1107 : : /* Broadcast to the network
1108 : : */
1109 : 0 : address = g_inet_socket_address_new_from_string (self->broadcast_address,
1110 : 0 : self->port);
1111 [ # # ]: 0 : valent_lan_channel_service_socket_queue (self, address);
1112 : : }
1113 : : }
1114 : :
1115 : : /*
1116 : : * GInitable
1117 : : */
1118 : : static gboolean
1119 : 3 : valent_lan_channel_service_init_sync (GInitable *initable,
1120 : : GCancellable *cancellable,
1121 : : GError **error)
1122 : : {
1123 : 3 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (initable);
1124 : :
1125 [ - + ]: 3 : g_assert (VALENT_IS_LAN_CHANNEL_SERVICE (initable));
1126 [ - + - - : 3 : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
1127 : :
1128 : 3 : self->network_available = g_network_monitor_get_network_available (self->monitor);
1129 : 3 : g_signal_connect_object (self->monitor,
1130 : : "network-changed",
1131 : : G_CALLBACK (on_network_changed),
1132 : : self,
1133 : : G_CONNECT_DEFAULT);
1134 : :
1135 [ - + ]: 3 : if (!valent_lan_channel_service_tcp_setup (self, cancellable, error))
1136 : : return FALSE;
1137 : :
1138 [ - + ]: 3 : if (!valent_lan_channel_service_udp_setup (self, cancellable, error))
1139 : : return FALSE;
1140 : :
1141 : 3 : self->dnssd = valent_lan_dnssd_new (NULL);
1142 : 3 : g_object_bind_property (self, "identity",
1143 : : self->dnssd, "identity",
1144 : : G_BINDING_SYNC_CREATE);
1145 : 3 : g_signal_connect_object (self->dnssd,
1146 : : "items-changed",
1147 : : G_CALLBACK (on_items_changed),
1148 : : self,
1149 : : G_CONNECT_DEFAULT);
1150 : 3 : valent_lan_dnssd_start (VALENT_LAN_DNSSD (self->dnssd));
1151 : :
1152 : 3 : return TRUE;
1153 : : }
1154 : :
1155 : : static void
1156 : 1 : g_initable_iface_init (GInitableIface *iface)
1157 : : {
1158 : 1 : iface->init = valent_lan_channel_service_init_sync;
1159 : 1 : }
1160 : :
1161 : : /*
1162 : : * ValentObject
1163 : : */
1164 : : static void
1165 : 6 : valent_lan_channel_service_destroy (ValentObject *object)
1166 : : {
1167 : 6 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (object);
1168 : :
1169 : 6 : g_signal_handlers_disconnect_by_data (self->monitor, self);
1170 : :
1171 [ + + ]: 6 : if (self->dnssd != NULL)
1172 : : {
1173 : 3 : g_signal_handlers_disconnect_by_data (self->dnssd, self);
1174 [ + - ]: 3 : g_clear_object (&self->dnssd);
1175 : : }
1176 : :
1177 [ - + ]: 6 : g_clear_object (&self->udp_socket4);
1178 [ + + ]: 6 : g_clear_object (&self->udp_socket6);
1179 : :
1180 [ + + ]: 6 : if (self->listener != NULL)
1181 : : {
1182 : 3 : g_socket_service_stop (G_SOCKET_SERVICE (self->listener));
1183 : 3 : g_socket_listener_close (G_SOCKET_LISTENER (self->listener));
1184 [ + - ]: 3 : g_clear_object (&self->listener);
1185 : : }
1186 : :
1187 : 6 : VALENT_OBJECT_CLASS (valent_lan_channel_service_parent_class)->destroy (object);
1188 : 6 : }
1189 : :
1190 : : /*
1191 : : * GObject
1192 : : */
1193 : : static void
1194 : 3 : valent_lan_channel_service_finalize (GObject *object)
1195 : : {
1196 : 3 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (object);
1197 : :
1198 [ + - ]: 3 : g_clear_pointer (&self->broadcast_address, g_free);
1199 [ + - ]: 3 : g_clear_pointer (&self->channels, g_hash_table_unref);
1200 : :
1201 : 3 : G_OBJECT_CLASS (valent_lan_channel_service_parent_class)->finalize (object);
1202 : 3 : }
1203 : :
1204 : : static void
1205 : 0 : valent_lan_channel_service_get_property (GObject *object,
1206 : : guint prop_id,
1207 : : GValue *value,
1208 : : GParamSpec *pspec)
1209 : : {
1210 : 0 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (object);
1211 : :
1212 [ # # # ]: 0 : switch ((ValentLanChannelServiceProperty)prop_id)
1213 : : {
1214 : 0 : case PROP_BROADCAST_ADDRESS:
1215 : 0 : g_value_set_string (value, self->broadcast_address);
1216 : 0 : break;
1217 : :
1218 : 0 : case PROP_PORT:
1219 : 0 : g_value_set_uint (value, self->port);
1220 : 0 : break;
1221 : :
1222 : 0 : default:
1223 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1224 : : }
1225 : 0 : }
1226 : :
1227 : : static void
1228 : 6 : valent_lan_channel_service_set_property (GObject *object,
1229 : : guint prop_id,
1230 : : const GValue *value,
1231 : : GParamSpec *pspec)
1232 : : {
1233 : 6 : ValentLanChannelService *self = VALENT_LAN_CHANNEL_SERVICE (object);
1234 : :
1235 [ + + - ]: 6 : switch ((ValentLanChannelServiceProperty)prop_id)
1236 : : {
1237 : 3 : case PROP_BROADCAST_ADDRESS:
1238 : 3 : self->broadcast_address = g_value_dup_string (value);
1239 : 3 : break;
1240 : :
1241 : 3 : case PROP_PORT:
1242 : 3 : self->port = g_value_get_uint (value);
1243 : 3 : break;
1244 : :
1245 : 0 : default:
1246 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1247 : : }
1248 : 6 : }
1249 : :
1250 : : static void
1251 : 1 : valent_lan_channel_service_class_init (ValentLanChannelServiceClass *klass)
1252 : : {
1253 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
1254 : 1 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
1255 : 1 : ValentChannelServiceClass *service_class = VALENT_CHANNEL_SERVICE_CLASS (klass);
1256 : :
1257 : 1 : object_class->finalize = valent_lan_channel_service_finalize;
1258 : 1 : object_class->get_property = valent_lan_channel_service_get_property;
1259 : 1 : object_class->set_property = valent_lan_channel_service_set_property;
1260 : :
1261 : 1 : vobject_class->destroy = valent_lan_channel_service_destroy;
1262 : :
1263 : 1 : service_class->build_identity = valent_lan_channel_service_build_identity;
1264 : 1 : service_class->channel = valent_lan_channel_service_channel;
1265 : 1 : service_class->identify = valent_lan_channel_service_identify;
1266 : :
1267 : : /**
1268 : : * ValentLanChannelService:broadcast-address:
1269 : : *
1270 : : * The UDP broadcast address for the service.
1271 : : *
1272 : : * This available as a construct property primarily for use in unit tests.
1273 : : */
1274 : 2 : properties [PROP_BROADCAST_ADDRESS] =
1275 : 1 : g_param_spec_string ("broadcast-address", NULL, NULL,
1276 : : VALENT_LAN_PROTOCOL_ADDR,
1277 : : (G_PARAM_READWRITE |
1278 : : G_PARAM_CONSTRUCT_ONLY |
1279 : : G_PARAM_EXPLICIT_NOTIFY |
1280 : : G_PARAM_STATIC_STRINGS));
1281 : :
1282 : : /**
1283 : : * ValentLanChannelService:port:
1284 : : *
1285 : : * The TCP/IP port for the service.
1286 : : *
1287 : : * The current KDE Connect protocol (v7) defines port 1716 as the default.
1288 : : *
1289 : : * This available as a construct property primarily for use in unit tests.
1290 : : */
1291 : 2 : properties [PROP_PORT] =
1292 : 1 : g_param_spec_uint ("port", NULL, NULL,
1293 : : VALENT_LAN_PROTOCOL_PORT_MIN, VALENT_LAN_PROTOCOL_PORT_MAX,
1294 : : VALENT_LAN_PROTOCOL_PORT,
1295 : : (G_PARAM_READWRITE |
1296 : : G_PARAM_CONSTRUCT_ONLY |
1297 : : G_PARAM_EXPLICIT_NOTIFY |
1298 : : G_PARAM_STATIC_STRINGS));
1299 : :
1300 : 1 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
1301 : 1 : }
1302 : :
1303 : : static void
1304 : 3 : valent_lan_channel_service_init (ValentLanChannelService *self)
1305 : : {
1306 : 3 : self->channels = g_hash_table_new_full (g_str_hash,
1307 : : g_str_equal,
1308 : : g_free,
1309 : : g_object_unref);
1310 : 3 : self->monitor = g_network_monitor_get_default ();
1311 : 3 : }
1312 : :
|