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