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