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