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