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