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-channel"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <time.h>
9 : :
10 : : #include <gio/gio.h>
11 : : #include <json-glib/json-glib.h>
12 : : #include <libvalent-core.h>
13 : :
14 : : #include "valent-certificate.h"
15 : : #include "valent-packet.h"
16 : :
17 : : #include "valent-channel.h"
18 : :
19 : :
20 : : /**
21 : : * ValentChannel:
22 : : *
23 : : * A base class for device connections.
24 : : *
25 : : * `ValentChannel` is a base class for the primary communication channel in
26 : : * Valent. It is effectively an abstraction layer around a [class@Gio.IOStream].
27 : : *
28 : : * ## Packet Exchange
29 : : *
30 : : * The core of the KDE Connect protocol is built on the exchange of JSON
31 : : * packets, similar to JSON-RPC. Packets can be queued concurrently from
32 : : * different threads with [method@Valent.Channel.write_packet] and read
33 : : * sequentially with [method@Valent.Channel.read_packet].
34 : : *
35 : : * Packets may contain payload information, allowing devices to negotiate
36 : : * auxiliary connections. Incoming connections can be accepted by passing the
37 : : * packet to [method@Valent.Channel.download], or opened by passing the packet
38 : : * to [method@Valent.Channel.upload].
39 : : *
40 : : * ## Implementation Notes
41 : : *
42 : : * Implementations should override [vfunc@Valent.Channel.download] and
43 : : * [vfunc@Valent.Channel.upload] to support accepting and opening auxiliary
44 : : * connections, respectively. To know when to store persistent data related to
45 : : * the connection, override [vfunc@Valent.Channel.store_data].
46 : : *
47 : : * Since: 1.0
48 : : */
49 : :
50 : : typedef struct
51 : : {
52 : : GIOStream *base_stream;
53 : : GTlsCertificate *certificate;
54 : : JsonNode *identity;
55 : : GTlsCertificate *peer_certificate;
56 : : JsonNode *peer_identity;
57 : : char *verification_key;
58 : :
59 : : /* Packet Buffer */
60 : : GDataInputStream *input_buffer;
61 : : GMainLoop *output_buffer;
62 : : } ValentChannelPrivate;
63 : :
64 [ + + + - ]: 6633 : G_DEFINE_TYPE_WITH_PRIVATE (ValentChannel, valent_channel, VALENT_TYPE_OBJECT)
65 : :
66 : : typedef enum {
67 : : PROP_BASE_STREAM = 1,
68 : : PROP_CERTIFICATE,
69 : : PROP_IDENTITY,
70 : : PROP_PEER_CERTIFICATE,
71 : : PROP_PEER_IDENTITY,
72 : : } ValentChannelProperty;
73 : :
74 : : static GParamSpec *properties[PROP_PEER_IDENTITY + 1] = { NULL, };
75 : :
76 : :
77 : : /* LCOV_EXCL_START */
78 : : static GIOStream *
79 : : valent_channel_real_download (ValentChannel *channel,
80 : : JsonNode *packet,
81 : : GCancellable *cancellable,
82 : : GError **error)
83 : : {
84 : : g_set_error (error,
85 : : G_IO_ERROR,
86 : : G_IO_ERROR_NOT_SUPPORTED,
87 : : "%s does not implement download()",
88 : : G_OBJECT_TYPE_NAME (channel));
89 : : return NULL;
90 : : }
91 : :
92 : : static void
93 : : valent_channel_real_download_task (GTask *task,
94 : : gpointer source_object,
95 : : gpointer task_data,
96 : : GCancellable *cancellable)
97 : : {
98 : : ValentChannel *self = source_object;
99 : : JsonNode *packet = task_data;
100 : : g_autoptr (GIOStream) stream = NULL;
101 : : GError *error = NULL;
102 : :
103 : : if (g_task_return_error_if_cancelled (task))
104 : : return;
105 : :
106 : : stream = valent_channel_download (self, packet, cancellable, &error);
107 : : if (stream != NULL)
108 : : g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
109 : : else
110 : : g_task_return_error (task, error);
111 : : }
112 : :
113 : : static void
114 : : valent_channel_real_download_async (ValentChannel *channel,
115 : : JsonNode *packet,
116 : : GCancellable *cancellable,
117 : : GAsyncReadyCallback callback,
118 : : gpointer user_data)
119 : : {
120 : : g_autoptr (GTask) task = NULL;
121 : :
122 : : g_assert (VALENT_IS_CHANNEL (channel));
123 : : g_assert (VALENT_IS_PACKET (packet));
124 : : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
125 : :
126 : : task = g_task_new (channel, cancellable, callback, user_data);
127 : : g_task_set_source_tag (task, valent_channel_real_download_async);
128 : : g_task_set_task_data (task,
129 : : json_node_ref (packet),
130 : : (GDestroyNotify)json_node_unref);
131 : : g_task_run_in_thread (task, valent_channel_real_download_task);
132 : : }
133 : :
134 : : static GIOStream *
135 : : valent_channel_real_download_finish (ValentChannel *channel,
136 : : GAsyncResult *result,
137 : : GError **error)
138 : : {
139 : : g_assert (VALENT_IS_CHANNEL (channel));
140 : : g_assert (g_task_is_valid (result, channel));
141 : : g_assert (error == NULL || *error == NULL);
142 : :
143 : : return g_task_propagate_pointer (G_TASK (result), error);
144 : : }
145 : :
146 : : static GIOStream *
147 : : valent_channel_real_upload (ValentChannel *channel,
148 : : JsonNode *packet,
149 : : GCancellable *cancellable,
150 : : GError **error)
151 : : {
152 : : g_set_error (error,
153 : : G_IO_ERROR,
154 : : G_IO_ERROR_NOT_SUPPORTED,
155 : : "%s does not implement upload()",
156 : : G_OBJECT_TYPE_NAME (channel));
157 : : return NULL;
158 : : }
159 : :
160 : : static void
161 : : valent_channel_upload_task (GTask *task,
162 : : gpointer source_object,
163 : : gpointer task_data,
164 : : GCancellable *cancellable)
165 : : {
166 : : ValentChannel *self = source_object;
167 : : JsonNode *packet = task_data;
168 : : g_autoptr (GIOStream) stream = NULL;
169 : : GError *error = NULL;
170 : :
171 : : if (g_task_return_error_if_cancelled (task))
172 : : return;
173 : :
174 : : stream = valent_channel_upload (self, packet, cancellable, &error);
175 : : if (stream != NULL)
176 : : g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
177 : : else
178 : : g_task_return_error (task, error);
179 : : }
180 : :
181 : : static void
182 : : valent_channel_real_upload_async (ValentChannel *channel,
183 : : JsonNode *packet,
184 : : GCancellable *cancellable,
185 : : GAsyncReadyCallback callback,
186 : : gpointer user_data)
187 : : {
188 : : g_autoptr (GTask) task = NULL;
189 : :
190 : : g_assert (VALENT_IS_CHANNEL (channel));
191 : : g_assert (VALENT_IS_PACKET (packet));
192 : : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
193 : :
194 : : task = g_task_new (channel, cancellable, callback, user_data);
195 : : g_task_set_source_tag (task, valent_channel_real_upload_async);
196 : : g_task_set_task_data (task,
197 : : json_node_ref (packet),
198 : : (GDestroyNotify)json_node_unref);
199 : : g_task_run_in_thread (task, valent_channel_upload_task);
200 : : }
201 : :
202 : : static GIOStream *
203 : : valent_channel_real_upload_finish (ValentChannel *channel,
204 : : GAsyncResult *result,
205 : : GError **error)
206 : : {
207 : : g_assert (VALENT_IS_CHANNEL (channel));
208 : : g_assert (g_task_is_valid (result, channel));
209 : : g_assert (error == NULL || *error == NULL);
210 : :
211 : : return g_task_propagate_pointer (G_TASK (result), error);
212 : : }
213 : :
214 : : static void
215 : : valent_channel_real_store_data (ValentChannel *channel,
216 : : ValentContext *context)
217 : : {
218 : : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
219 : :
220 : : g_assert (VALENT_IS_CHANNEL (channel));
221 : : g_assert (VALENT_IS_CONTEXT (context));
222 : :
223 : : if (priv->certificate != NULL)
224 : : {
225 : : g_autofree char *certificate_pem = NULL;
226 : : g_autoptr (GFile) certificate_file = NULL;
227 : : g_autoptr (GError) error = NULL;
228 : :
229 : : g_object_get (priv->certificate,
230 : : "certificate-pem", &certificate_pem,
231 : : NULL);
232 : : certificate_file = valent_context_get_config_file (context,
233 : : "certificate.pem");
234 : : g_file_set_contents_full (g_file_peek_path (certificate_file),
235 : : certificate_pem,
236 : : strlen (certificate_pem),
237 : : G_FILE_SET_CONTENTS_DURABLE,
238 : : 0600,
239 : : &error);
240 : :
241 : : if (error != NULL)
242 : : {
243 : : g_warning ("%s(): failed to write \"%s\": %s",
244 : : G_STRFUNC,
245 : : g_file_peek_path (certificate_file),
246 : : error->message);
247 : : }
248 : : }
249 : : }
250 : : /* LCOV_EXCL_STOP */
251 : :
252 : :
253 : : /*
254 : : * ValentChannel
255 : : */
256 : : static inline gboolean
257 : 942 : valent_channel_return_error_if_closed (ValentChannel *self,
258 : : GTask *task)
259 : : {
260 : 942 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
261 : :
262 [ - + ]: 942 : if (g_task_return_error_if_cancelled (task))
263 : : return TRUE;
264 : :
265 : 942 : valent_object_lock (VALENT_OBJECT (self));
266 [ + - + + ]: 942 : if (priv->base_stream == NULL || g_io_stream_is_closed (priv->base_stream))
267 : : {
268 [ - + ]: 6 : if (priv->output_buffer != NULL)
269 : 0 : g_main_loop_quit (priv->output_buffer);
270 [ - + ]: 6 : g_clear_pointer (&priv->output_buffer, g_main_loop_unref);
271 [ - + ]: 6 : g_clear_object (&priv->input_buffer);
272 : 6 : valent_object_unlock (VALENT_OBJECT (self));
273 : :
274 : 6 : g_task_return_new_error (task,
275 : : G_IO_ERROR,
276 : : G_IO_ERROR_CONNECTION_CLOSED,
277 : : "Channel is closed");
278 : 6 : return TRUE;
279 : : }
280 : :
281 : : return FALSE;
282 : : }
283 : :
284 : : static gpointer
285 : 206 : valent_channel_write_packet_worker (gpointer data)
286 : : {
287 : 397 : g_autoptr (GMainLoop) loop = (GMainLoop *)data;
288 : 206 : GMainContext *context = g_main_loop_get_context (loop);
289 : :
290 : : /* The loop quits when the channel is closed, then the context is drained to
291 : : * ensure all tasks return. */
292 : 206 : g_main_context_push_thread_default (context);
293 : :
294 : 206 : g_main_loop_run (loop);
295 : :
296 [ - + ]: 206 : while (g_main_context_pending (context))
297 : 0 : g_main_context_iteration (NULL, FALSE);
298 : :
299 : 191 : g_main_context_pop_thread_default (context);
300 : :
301 [ + - ]: 191 : return NULL;
302 : : }
303 : :
304 : : static void
305 : 206 : valent_channel_set_base_stream (ValentChannel *self,
306 : : GIOStream *base_stream)
307 : : {
308 : 206 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
309 : :
310 [ + - ]: 206 : g_assert (VALENT_IS_CHANNEL (self));
311 : :
312 [ + - ]: 206 : if (base_stream != NULL)
313 : : {
314 : 412 : g_autoptr (GMainContext) context = NULL;
315 : 206 : GInputStream *input_stream;
316 : 206 : GThread *thread;
317 : :
318 : 206 : valent_object_lock (VALENT_OBJECT (self));
319 : 206 : input_stream = g_io_stream_get_input_stream (base_stream);
320 : :
321 : 206 : priv->base_stream = g_object_ref (base_stream);
322 : 206 : priv->input_buffer = g_object_new (G_TYPE_DATA_INPUT_STREAM,
323 : : "base-stream", input_stream,
324 : : "close-base-stream", FALSE,
325 : : NULL);
326 : :
327 : 206 : context = g_main_context_new ();
328 : 206 : priv->output_buffer = g_main_loop_new (context, FALSE);
329 : 206 : thread = g_thread_new ("valent-channel",
330 : : valent_channel_write_packet_worker,
331 : 206 : g_main_loop_ref (priv->output_buffer));
332 [ + - ]: 206 : g_clear_pointer (&thread, g_thread_unref);
333 [ + - ]: 206 : valent_object_unlock (VALENT_OBJECT (self));
334 : : }
335 : 206 : }
336 : :
337 : :
338 : : /*
339 : : * GObject
340 : : */
341 : : static void
342 : 205 : valent_channel_finalize (GObject *object)
343 : : {
344 : 205 : ValentChannel *self = VALENT_CHANNEL (object);
345 : 205 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
346 : :
347 : 205 : valent_object_lock (VALENT_OBJECT (self));
348 [ + + ]: 205 : g_clear_pointer (&priv->output_buffer, g_main_loop_unref);
349 [ + + ]: 205 : g_clear_object (&priv->input_buffer);
350 [ + - ]: 205 : g_clear_object (&priv->base_stream);
351 [ + + ]: 205 : g_clear_object (&priv->certificate);
352 [ + - ]: 205 : g_clear_pointer (&priv->identity, json_node_unref);
353 [ + + ]: 205 : g_clear_object (&priv->peer_certificate);
354 [ + - ]: 205 : g_clear_pointer (&priv->peer_identity, json_node_unref);
355 [ + + ]: 205 : g_clear_pointer (&priv->verification_key, g_free);
356 : 205 : valent_object_unlock (VALENT_OBJECT (self));
357 : :
358 : 205 : G_OBJECT_CLASS (valent_channel_parent_class)->finalize (object);
359 : 205 : }
360 : :
361 : : static void
362 : 3 : valent_channel_get_property (GObject *object,
363 : : guint prop_id,
364 : : GValue *value,
365 : : GParamSpec *pspec)
366 : : {
367 : 3 : ValentChannel *self = VALENT_CHANNEL (object);
368 : 3 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
369 : :
370 [ + - + - : 3 : switch ((ValentChannelProperty)prop_id)
+ - ]
371 : : {
372 : 1 : case PROP_BASE_STREAM:
373 : 1 : g_value_take_object (value, valent_channel_ref_base_stream (self));
374 : 1 : break;
375 : :
376 : 0 : case PROP_CERTIFICATE:
377 : 0 : g_value_set_object (value, priv->certificate);
378 : 0 : break;
379 : :
380 : 1 : case PROP_IDENTITY:
381 : 1 : g_value_set_boxed (value, priv->identity);
382 : 1 : break;
383 : :
384 : 0 : case PROP_PEER_CERTIFICATE:
385 : 0 : g_value_set_object (value, priv->peer_certificate);
386 : 0 : break;
387 : :
388 : 1 : case PROP_PEER_IDENTITY:
389 : 1 : g_value_set_boxed (value, priv->peer_identity);
390 : 1 : break;
391 : :
392 : 0 : default:
393 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
394 : : }
395 : 3 : }
396 : :
397 : : static void
398 : 1030 : valent_channel_set_property (GObject *object,
399 : : guint prop_id,
400 : : const GValue *value,
401 : : GParamSpec *pspec)
402 : : {
403 : 1030 : ValentChannel *self = VALENT_CHANNEL (object);
404 : 1030 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
405 : :
406 [ + + + + : 1030 : switch ((ValentChannelProperty)prop_id)
+ - ]
407 : : {
408 : 206 : case PROP_BASE_STREAM:
409 : 206 : valent_channel_set_base_stream (self, g_value_get_object (value));
410 : 206 : break;
411 : :
412 : 206 : case PROP_CERTIFICATE:
413 : 206 : priv->certificate = g_value_dup_object (value);
414 : 206 : break;
415 : :
416 : 206 : case PROP_IDENTITY:
417 : 206 : priv->identity = g_value_dup_boxed (value);
418 : 206 : break;
419 : :
420 : 206 : case PROP_PEER_CERTIFICATE:
421 : 206 : priv->peer_certificate = g_value_dup_object (value);
422 : 206 : break;
423 : :
424 : 206 : case PROP_PEER_IDENTITY:
425 : 206 : priv->peer_identity = g_value_dup_boxed (value);
426 : 206 : break;
427 : :
428 : 0 : default:
429 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
430 : : }
431 : 1030 : }
432 : :
433 : : static void
434 : 31 : valent_channel_class_init (ValentChannelClass *klass)
435 : : {
436 : 31 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
437 : :
438 : 31 : object_class->finalize = valent_channel_finalize;
439 : 31 : object_class->get_property = valent_channel_get_property;
440 : 31 : object_class->set_property = valent_channel_set_property;
441 : :
442 : 31 : klass->download = valent_channel_real_download;
443 : 31 : klass->download_async = valent_channel_real_download_async;
444 : 31 : klass->download_finish = valent_channel_real_download_finish;
445 : 31 : klass->upload = valent_channel_real_upload;
446 : 31 : klass->upload_async = valent_channel_real_upload_async;
447 : 31 : klass->upload_finish = valent_channel_real_upload_finish;
448 : 31 : klass->store_data = valent_channel_real_store_data;
449 : :
450 : : /**
451 : : * ValentChannel:base-stream: (getter ref_base_stream)
452 : : *
453 : : * The base [class@Gio.IOStream] for the channel.
454 : : *
455 : : * Implementations of [class@Valent.ChannelService] must set this property
456 : : * during construction.
457 : : *
458 : : * Since: 1.0
459 : : */
460 : 62 : properties [PROP_BASE_STREAM] =
461 : 31 : g_param_spec_object ("base-stream", NULL, NULL,
462 : : G_TYPE_IO_STREAM,
463 : : (G_PARAM_READWRITE |
464 : : G_PARAM_CONSTRUCT_ONLY |
465 : : G_PARAM_EXPLICIT_NOTIFY |
466 : : G_PARAM_STATIC_STRINGS));
467 : :
468 : : /**
469 : : * ValentChannel:certificate: (getter get_certificate)
470 : : *
471 : : * The peer TLS certificate.
472 : : *
473 : : * This is the TLS certificate sent by the [class@Valent.ChannelService]
474 : : * implementation to identify the host system.
475 : : *
476 : : * Implementations of [class@Valent.ChannelService] must set this property
477 : : * during construction.
478 : : *
479 : : * Since: 1.0
480 : : */
481 : 62 : properties [PROP_CERTIFICATE] =
482 : 31 : g_param_spec_object ("certificate", NULL, NULL,
483 : : G_TYPE_TLS_CERTIFICATE,
484 : : (G_PARAM_READWRITE |
485 : : G_PARAM_CONSTRUCT_ONLY |
486 : : G_PARAM_EXPLICIT_NOTIFY |
487 : : G_PARAM_STATIC_STRINGS));
488 : :
489 : : /**
490 : : * ValentChannel:identity: (getter get_identity)
491 : : *
492 : : * The local identity packet.
493 : : *
494 : : * This is the identity packet sent by the [class@Valent.ChannelService]
495 : : * implementation to identify the host system.
496 : : *
497 : : * Implementations of [class@Valent.ChannelService] must set this property
498 : : * during construction.
499 : : *
500 : : * Since: 1.0
501 : : */
502 : 62 : properties [PROP_IDENTITY] =
503 : 31 : g_param_spec_boxed ("identity", NULL, NULL,
504 : : JSON_TYPE_NODE,
505 : : (G_PARAM_READWRITE |
506 : : G_PARAM_CONSTRUCT_ONLY |
507 : : G_PARAM_EXPLICIT_NOTIFY |
508 : : G_PARAM_STATIC_STRINGS));
509 : :
510 : : /**
511 : : * ValentChannel:peer-certificate: (getter get_peer_certificate)
512 : : *
513 : : * The peer TLS certificate.
514 : : *
515 : : * This is the TLS certificate sent by the peer to identify itself.
516 : : *
517 : : * Implementations of [class@Valent.ChannelService] must set this property
518 : : * during construction.
519 : : *
520 : : * Since: 1.0
521 : : */
522 : 62 : properties [PROP_PEER_CERTIFICATE] =
523 : 31 : g_param_spec_object ("peer-certificate", NULL, NULL,
524 : : G_TYPE_TLS_CERTIFICATE,
525 : : (G_PARAM_READWRITE |
526 : : G_PARAM_CONSTRUCT_ONLY |
527 : : G_PARAM_EXPLICIT_NOTIFY |
528 : : G_PARAM_STATIC_STRINGS));
529 : :
530 : : /**
531 : : * ValentChannel:peer-identity: (getter get_peer_identity)
532 : : *
533 : : * The peer identity packet.
534 : : *
535 : : * This is the identity packet sent by the peer to identify itself.
536 : : *
537 : : * Implementations of [class@Valent.ChannelService] must set this property
538 : : * during construction.
539 : : *
540 : : * Since: 1.0
541 : : */
542 : 62 : properties [PROP_PEER_IDENTITY] =
543 : 31 : g_param_spec_boxed ("peer-identity", NULL, NULL,
544 : : JSON_TYPE_NODE,
545 : : (G_PARAM_READWRITE |
546 : : G_PARAM_CONSTRUCT_ONLY |
547 : : G_PARAM_EXPLICIT_NOTIFY |
548 : : G_PARAM_STATIC_STRINGS));
549 : :
550 : 31 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
551 : 31 : }
552 : :
553 : : static void
554 : 206 : valent_channel_init (ValentChannel *self)
555 : : {
556 : 206 : }
557 : :
558 : : /**
559 : : * valent_channel_ref_base_stream: (get-property base-stream)
560 : : * @channel: a `ValentChannel`
561 : : *
562 : : * Get the base [class@Gio.IOStream].
563 : : *
564 : : * Returns: (transfer full) (nullable): the base stream
565 : : *
566 : : * Since: 1.0
567 : : */
568 : : GIOStream *
569 : 1 : valent_channel_ref_base_stream (ValentChannel *channel)
570 : : {
571 : 1 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
572 : 1 : GIOStream *ret = NULL;
573 : :
574 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
575 : :
576 : 1 : valent_object_lock (VALENT_OBJECT (channel));
577 [ + - ]: 1 : if (priv->base_stream != NULL)
578 : 1 : ret = g_object_ref (priv->base_stream);
579 : 1 : valent_object_unlock (VALENT_OBJECT (channel));
580 : :
581 : 1 : return g_steal_pointer (&ret);
582 : : }
583 : :
584 : : /**
585 : : * valent_channel_get_certificate: (get-property certificate)
586 : : * @channel: A `ValentChannel`
587 : : *
588 : : * Get the TLS certificate.
589 : : *
590 : : * Returns: (nullable) (transfer none): a TLS certificate
591 : : *
592 : : * Since: 1.0
593 : : */
594 : : GTlsCertificate *
595 : 8 : valent_channel_get_certificate (ValentChannel *channel)
596 : : {
597 : 8 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
598 : :
599 [ + - ]: 8 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
600 : :
601 : 8 : return priv->certificate;
602 : : }
603 : :
604 : : /**
605 : : * valent_channel_get_identity: (get-property identity)
606 : : * @channel: A `ValentChannel`
607 : : *
608 : : * Get the local identity packet.
609 : : *
610 : : * Returns: (transfer none): a KDE Connect packet
611 : : *
612 : : * Since: 1.0
613 : : */
614 : : JsonNode *
615 : 1 : valent_channel_get_identity (ValentChannel *channel)
616 : : {
617 : 1 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
618 : :
619 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
620 : :
621 : 1 : return priv->identity;
622 : : }
623 : :
624 : : /**
625 : : * valent_channel_get_peer_certificate: (get-property peer-certificate)
626 : : * @channel: A `ValentChannel`
627 : : *
628 : : * Get the peer TLS certificate.
629 : : *
630 : : * Returns: (nullable) (transfer none): a TLS certificate
631 : : *
632 : : * Since: 1.0
633 : : */
634 : : GTlsCertificate *
635 : 11 : valent_channel_get_peer_certificate (ValentChannel *channel)
636 : : {
637 : 11 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
638 : :
639 [ + - ]: 11 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
640 : :
641 : 11 : return priv->peer_certificate;
642 : : }
643 : :
644 : : /**
645 : : * valent_channel_get_peer_identity: (get-property peer-identity)
646 : : * @channel: A `ValentChannel`
647 : : *
648 : : * Get the peer identity packet.
649 : : *
650 : : * Returns: (transfer none): a KDE Connect packet
651 : : *
652 : : * Since: 1.0
653 : : */
654 : : JsonNode *
655 : 83 : valent_channel_get_peer_identity (ValentChannel *channel)
656 : : {
657 : 83 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
658 : :
659 [ + - ]: 83 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
660 : :
661 : 83 : return priv->peer_identity;
662 : : }
663 : :
664 : : /**
665 : : * valent_channel_get_verification_key:
666 : : * @channel: a `ValentChannel`
667 : : *
668 : : * Get a verification key for the connection.
669 : : *
670 : : * Returns: (nullable) (transfer none): a verification key
671 : : *
672 : : * Since: 1.0
673 : : */
674 : : const char *
675 : 4 : valent_channel_get_verification_key (ValentChannel *channel)
676 : : {
677 : 4 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
678 : :
679 [ + - ]: 4 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
680 : :
681 [ + - ]: 4 : if (priv->verification_key == NULL)
682 : : {
683 : 6 : g_autoptr (GChecksum) checksum = NULL;
684 : 4 : GTlsCertificate *cert = NULL;
685 : 4 : GTlsCertificate *peer_cert = NULL;
686 : 4 : GByteArray *pubkey;
687 : 4 : GByteArray *peer_pubkey;
688 : 4 : size_t cmplen;
689 : :
690 : 4 : cert = valent_channel_get_certificate (channel);
691 : 4 : peer_cert = valent_channel_get_peer_certificate (channel);
692 [ + + ]: 4 : if (cert == NULL || peer_cert == NULL)
693 : : return NULL;
694 : :
695 : 2 : pubkey = valent_certificate_get_public_key (cert);
696 : 2 : peer_pubkey = valent_certificate_get_public_key (peer_cert);
697 [ - + ]: 2 : if (pubkey == NULL || peer_pubkey == NULL)
698 : : return NULL;
699 : :
700 : 2 : checksum = g_checksum_new (G_CHECKSUM_SHA256);
701 : 2 : cmplen = MIN (pubkey->len, peer_pubkey->len);
702 : :
703 [ + + ]: 2 : if (memcmp (pubkey->data, peer_pubkey->data, cmplen) > 0)
704 : : {
705 : 1 : g_checksum_update (checksum, pubkey->data, pubkey->len);
706 : 1 : g_checksum_update (checksum, peer_pubkey->data, peer_pubkey->len);
707 : : }
708 : : else
709 : : {
710 : 1 : g_checksum_update (checksum, peer_pubkey->data, peer_pubkey->len);
711 : 1 : g_checksum_update (checksum, pubkey->data, pubkey->len);
712 : : }
713 : :
714 [ + - ]: 2 : priv->verification_key = g_strndup (g_checksum_get_string (checksum), 8);
715 : : }
716 : :
717 : 2 : return priv->verification_key;
718 : : }
719 : :
720 : : /**
721 : : * valent_channel_close:
722 : : * @channel: a `ValentChannel`
723 : : * @cancellable: (nullable): a `GCancellable`
724 : : * @error: (nullable): a `GError`
725 : : *
726 : : * Close the channel.
727 : : *
728 : : * Returns: %TRUE if successful, or %FALSE with @error set
729 : : */
730 : : gboolean
731 : 262 : valent_channel_close (ValentChannel *channel,
732 : : GCancellable *cancellable,
733 : : GError **error)
734 : : {
735 : 262 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
736 : 262 : gboolean ret = TRUE;
737 : :
738 : 262 : VALENT_ENTRY;
739 : :
740 [ + - ]: 262 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), FALSE);
741 [ - + - - : 262 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- - - - ]
742 [ + + - + ]: 262 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
743 : :
744 : 262 : valent_object_lock (VALENT_OBJECT (channel));
745 [ - + + + ]: 262 : if (priv->base_stream != NULL && !g_io_stream_is_closed (priv->base_stream))
746 : : {
747 : 192 : ret = g_io_stream_close (priv->base_stream, cancellable, error);
748 : :
749 [ + - ]: 192 : if (priv->output_buffer != NULL)
750 : 192 : g_main_loop_quit (priv->output_buffer);
751 [ + - ]: 192 : g_clear_pointer (&priv->output_buffer, g_main_loop_unref);
752 [ - + ]: 192 : g_clear_object (&priv->input_buffer);
753 : : }
754 : 262 : valent_object_unlock (VALENT_OBJECT (channel));
755 : :
756 : 262 : VALENT_RETURN (ret);
757 : : }
758 : :
759 : : static void
760 : 78 : valent_channel_close_task (GTask *task,
761 : : gpointer source_object,
762 : : gpointer task_data,
763 : : GCancellable *cancellable)
764 : : {
765 : 78 : ValentChannel *self = source_object;
766 : 78 : GError *error = NULL;
767 : :
768 [ - + ]: 78 : if (g_task_return_error_if_cancelled (task))
769 : 0 : return;
770 : :
771 [ + - ]: 78 : if (valent_channel_close (self, cancellable, &error))
772 : 78 : g_task_return_boolean (task, TRUE);
773 : : else
774 : 0 : g_task_return_error (task, error);
775 : : }
776 : :
777 : : /**
778 : : * valent_channel_close_async:
779 : : * @channel: a `ValentChannel`
780 : : * @cancellable: (nullable): a `GCancellable`
781 : : * @callback: (scope async): a `GAsyncReadyCallback`
782 : : * @user_data: user supplied data
783 : : *
784 : : * Close the channel asynchronously.
785 : : *
786 : : * Call [method@Valent.Channel.close_finish] to get the result.
787 : : *
788 : : * Since: 1.0
789 : : */
790 : : void
791 : 78 : valent_channel_close_async (ValentChannel *channel,
792 : : GCancellable *cancellable,
793 : : GAsyncReadyCallback callback,
794 : : gpointer user_data)
795 : : {
796 : 156 : g_autoptr (GTask) task = NULL;
797 : :
798 : 78 : VALENT_ENTRY;
799 : :
800 [ + - ]: 78 : g_return_if_fail (VALENT_IS_CHANNEL (channel));
801 [ - + - - : 78 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
802 : :
803 : 78 : task = g_task_new (channel, cancellable, callback, user_data);
804 [ + - ]: 78 : g_task_set_source_tag (task, valent_channel_close_async);
805 : 78 : g_task_run_in_thread (task, valent_channel_close_task);
806 : :
807 [ + - ]: 78 : VALENT_EXIT;
808 : : }
809 : :
810 : : /**
811 : : * valent_channel_close_finish:
812 : : * @channel: a `ValentChannel`
813 : : * @result: a `GAsyncResult`
814 : : * @error: (nullable): a `GError`
815 : : *
816 : : * Finish an operation started by [method@Valent.Channel.close_async].
817 : : *
818 : : * Returns: %TRUE if successful, or %FALSE with @error set
819 : : *
820 : : * Since: 1.0
821 : : */
822 : : gboolean
823 : 1 : valent_channel_close_finish (ValentChannel *channel,
824 : : GAsyncResult *result,
825 : : GError **error)
826 : : {
827 : 1 : gboolean ret;
828 : :
829 : 1 : VALENT_ENTRY;
830 : :
831 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), FALSE);
832 [ - + ]: 1 : g_return_val_if_fail (g_task_is_valid (result, channel), FALSE);
833 [ + - - + ]: 1 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
834 : :
835 : 1 : ret = g_task_propagate_boolean (G_TASK (result), error);
836 : :
837 : 1 : VALENT_RETURN (ret);
838 : : }
839 : :
840 : : static void
841 : 360 : valent_channel_read_packet_task (GTask *task,
842 : : gpointer source_object,
843 : : gpointer task_data,
844 : : GCancellable *cancellable)
845 : : {
846 : 360 : ValentChannel *self = VALENT_CHANNEL (source_object);
847 : 360 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
848 : 360 : g_autoptr (GDataInputStream) stream = NULL;
849 [ + - + + ]: 360 : g_autofree char *line = NULL;
850 : 360 : JsonNode *packet = NULL;
851 : 360 : GError *error = NULL;
852 : :
853 [ + + ]: 360 : if (valent_channel_return_error_if_closed (self, task))
854 : : return;
855 : :
856 : 354 : stream = g_object_ref (priv->input_buffer);
857 : 354 : valent_object_unlock (VALENT_OBJECT (self));
858 : :
859 : 354 : line = g_data_input_stream_read_line_utf8 (stream, NULL, cancellable, &error);
860 : :
861 [ + + ]: 354 : if (error != NULL)
862 : 6 : return g_task_return_error (task, error);
863 : :
864 [ + + ]: 348 : if (line == NULL)
865 : 66 : return g_task_return_new_error (task,
866 : : G_IO_ERROR,
867 : : G_IO_ERROR_CONNECTION_CLOSED,
868 : : "Channel is closed");
869 : :
870 [ - + ]: 282 : if ((packet = valent_packet_deserialize (line, &error)) == NULL)
871 : 0 : return g_task_return_error (task, error);
872 : :
873 : 282 : g_task_return_pointer (task, packet, (GDestroyNotify)json_node_unref);
874 : : }
875 : :
876 : : /**
877 : : * valent_channel_read_packet:
878 : : * @channel: a `ValentChannel`
879 : : * @cancellable: (nullable): a `GCancellable`
880 : : * @callback: (scope async): a `GAsyncReadyCallback`
881 : : * @user_data: user supplied data
882 : : *
883 : : * Read the next KDE Connect packet from @channel.
884 : : *
885 : : * Call [method@Valent.Channel.read_packet_finish] to get the result.
886 : : *
887 : : * Since: 1.0
888 : : */
889 : : void
890 : 360 : valent_channel_read_packet (ValentChannel *channel,
891 : : GCancellable *cancellable,
892 : : GAsyncReadyCallback callback,
893 : : gpointer user_data)
894 : : {
895 : 720 : g_autoptr (GTask) task = NULL;
896 : :
897 : 360 : VALENT_ENTRY;
898 : :
899 [ + - ]: 360 : g_return_if_fail (VALENT_IS_CHANNEL (channel));
900 [ - + - - : 360 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
901 : :
902 : 360 : task = g_task_new (channel, cancellable, callback, user_data);
903 [ + - ]: 360 : g_task_set_source_tag (task, valent_channel_read_packet);
904 : 360 : g_task_run_in_thread (task, valent_channel_read_packet_task);
905 : :
906 [ + - ]: 360 : VALENT_EXIT;
907 : : }
908 : :
909 : : /**
910 : : * valent_channel_read_packet_finish:
911 : : * @channel: a `ValentChannel`
912 : : * @result: a `GAsyncResult`
913 : : * @error: (nullable): a `GError`
914 : : *
915 : : * Finish an operation started by [method@Valent.Channel.read_packet].
916 : : *
917 : : * Returns: (transfer full): a KDE Connect packet, or %NULL with @error set
918 : : *
919 : : * Since: 1.0
920 : : */
921 : : JsonNode *
922 : 359 : valent_channel_read_packet_finish (ValentChannel *channel,
923 : : GAsyncResult *result,
924 : : GError **error)
925 : : {
926 : 359 : JsonNode *ret;
927 : :
928 : 359 : VALENT_ENTRY;
929 : :
930 [ + - ]: 359 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
931 [ - + ]: 359 : g_return_val_if_fail (g_task_is_valid (result, channel), NULL);
932 [ + - - + ]: 359 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
933 : :
934 : 359 : ret = g_task_propagate_pointer (G_TASK (result), error);
935 : :
936 : 359 : VALENT_RETURN (ret);
937 : : }
938 : :
939 : : static gboolean
940 : 291 : valent_channel_write_packet_func (gpointer data)
941 : : {
942 : 291 : GTask *task = G_TASK (data);
943 : 291 : ValentChannel *self = g_task_get_source_object (task);
944 : 291 : ValentChannelPrivate *priv = valent_channel_get_instance_private (self);
945 : 582 : g_autoptr (GOutputStream) stream = NULL;
946 : 291 : JsonNode *packet = NULL;
947 : 291 : GCancellable *cancellable = NULL;
948 : 291 : GError *error = NULL;
949 : :
950 [ + - + - : 291 : g_assert (G_IS_TASK (task));
- + - - ]
951 [ - + ]: 291 : g_assert (VALENT_IS_CHANNEL (self));
952 : :
953 [ + - ]: 291 : if (valent_channel_return_error_if_closed (self, task))
954 : : return G_SOURCE_REMOVE;
955 : :
956 : 291 : stream = g_object_ref (g_io_stream_get_output_stream (priv->base_stream));
957 : 291 : valent_object_unlock (VALENT_OBJECT (self));
958 : :
959 : 291 : packet = g_task_get_task_data (task);
960 : 291 : cancellable = g_task_get_cancellable (task);
961 : :
962 [ + + ]: 291 : if (valent_packet_to_stream (stream, packet, cancellable, &error))
963 : 286 : g_task_return_boolean (task, TRUE);
964 : : else
965 : 5 : g_task_return_error (task, error);
966 : :
967 [ + - ]: 291 : return G_SOURCE_REMOVE;
968 : : }
969 : :
970 : : /**
971 : : * valent_channel_write_packet:
972 : : * @channel: a `ValentChannel`
973 : : * @packet: a KDE Connect packet
974 : : * @cancellable: (nullable): a `GCancellable`
975 : : * @callback: (scope async): a `GAsyncReadyCallback`
976 : : * @user_data: user supplied data
977 : : *
978 : : * Send a packet over the channel.
979 : : *
980 : : * Internally [class@Valent.Channel] uses an outgoing packet buffer, so
981 : : * multiple requests can be started safely from any thread.
982 : : *
983 : : * Call [method@Valent.Channel.write_packet_finish] to get the result.
984 : : *
985 : : * Since: 1.0
986 : : */
987 : : void
988 : 291 : valent_channel_write_packet (ValentChannel *channel,
989 : : JsonNode *packet,
990 : : GCancellable *cancellable,
991 : : GAsyncReadyCallback callback,
992 : : gpointer user_data)
993 : : {
994 : 291 : ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);
995 : 582 : g_autoptr (GTask) task = NULL;
996 : :
997 : 291 : VALENT_ENTRY;
998 : :
999 [ + - ]: 291 : g_return_if_fail (VALENT_IS_CHANNEL (channel));
1000 [ - + ]: 291 : g_return_if_fail (VALENT_IS_PACKET (packet));
1001 [ + + + - : 291 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- + - - ]
1002 : :
1003 : 291 : task = g_task_new (channel, cancellable, callback, user_data);
1004 [ + - ]: 291 : g_task_set_source_tag (task, valent_channel_write_packet);
1005 : 291 : g_task_set_task_data (task,
1006 : 291 : json_node_ref (packet),
1007 : : (GDestroyNotify)json_node_unref);
1008 : :
1009 [ + - ]: 291 : if (valent_channel_return_error_if_closed (channel, task))
1010 : 291 : VALENT_EXIT;
1011 : :
1012 : 291 : g_main_context_invoke_full (g_main_loop_get_context (priv->output_buffer),
1013 : : g_task_get_priority (task),
1014 : : valent_channel_write_packet_func,
1015 : : g_object_ref (task),
1016 : : g_object_unref);
1017 : :
1018 : 291 : valent_object_unlock (VALENT_OBJECT (channel));
1019 : :
1020 [ + - ]: 582 : VALENT_EXIT;
1021 : : }
1022 : :
1023 : : /**
1024 : : * valent_channel_write_packet_finish:
1025 : : * @channel: a `ValentChannel`
1026 : : * @result: a `GAsyncResult`
1027 : : * @error: (nullable): a `GError`
1028 : : *
1029 : : * Finish an operation started by [method@Valent.Channel.write_packet].
1030 : : *
1031 : : * Returns: %TRUE if successful, or %FALSE with @error set
1032 : : *
1033 : : * Since: 1.0
1034 : : */
1035 : : gboolean
1036 : 256 : valent_channel_write_packet_finish (ValentChannel *channel,
1037 : : GAsyncResult *result,
1038 : : GError **error)
1039 : : {
1040 : 256 : gboolean ret;
1041 : :
1042 : 256 : VALENT_ENTRY;
1043 : :
1044 [ + - ]: 256 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), FALSE);
1045 [ - + ]: 256 : g_return_val_if_fail (g_task_is_valid (result, channel), FALSE);
1046 [ + - - + ]: 256 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1047 : :
1048 : 256 : ret = g_task_propagate_boolean (G_TASK (result), error);
1049 : :
1050 : 256 : VALENT_RETURN (ret);
1051 : : }
1052 : :
1053 : : /**
1054 : : * valent_channel_store_data: (virtual store_data)
1055 : : * @channel: a `ValentChannel`
1056 : : * @context: a `ValentContext`
1057 : : *
1058 : : * Store channel metadata.
1059 : : *
1060 : : * This method is called to store channel specific data. The default
1061 : : * implementation stores the peer certificate.
1062 : : *
1063 : : * Implementations that override [vfunc@Valent.Channel.store_data] must
1064 : : * chain-up.
1065 : : *
1066 : : * Since: 1.0
1067 : : */
1068 : : void
1069 : 5 : valent_channel_store_data (ValentChannel *channel,
1070 : : ValentContext *context)
1071 : : {
1072 : 5 : VALENT_ENTRY;
1073 : :
1074 [ + - ]: 5 : g_return_if_fail (VALENT_IS_CHANNEL (channel));
1075 [ - + ]: 5 : g_return_if_fail (VALENT_IS_CONTEXT (context));
1076 : :
1077 : 5 : VALENT_CHANNEL_GET_CLASS (channel)->store_data (channel, context);
1078 : :
1079 : 5 : VALENT_EXIT;
1080 : : }
1081 : :
1082 : : /**
1083 : : * valent_channel_download: (virtual download)
1084 : : * @channel: a `ValentChannel`
1085 : : * @packet: a KDE Connect packet
1086 : : * @cancellable: (nullable): a `GCancellable`
1087 : : * @error: (nullable): a `GError`
1088 : : *
1089 : : * Open an auxiliary connection, usually to download data.
1090 : : *
1091 : : * Implementations should use information from the `payloadTransferInfo` field
1092 : : * to open a connection and wait for it to be accepted. In most cases the remote
1093 : : * device will write data to the stream and then close it when finished.
1094 : : *
1095 : : * For example, a TCP-based implementation could connect to a port in the
1096 : : * `payloadTransferInfo` dictionary on the same host as the channel. When the
1097 : : * connection is accepted the caller can perform operations on it as required.
1098 : : *
1099 : : * Returns: (transfer full) (nullable): a `GIOStream`
1100 : : *
1101 : : * Since: 1.0
1102 : : */
1103 : : GIOStream *
1104 : 28 : valent_channel_download (ValentChannel *channel,
1105 : : JsonNode *packet,
1106 : : GCancellable *cancellable,
1107 : : GError **error)
1108 : : {
1109 : 28 : GIOStream *ret;
1110 : :
1111 : 28 : VALENT_ENTRY;
1112 : :
1113 [ + - ]: 28 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
1114 [ - + ]: 28 : g_return_val_if_fail (VALENT_IS_PACKET (packet), NULL);
1115 [ + + + - : 28 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- + - - ]
1116 [ + - - + ]: 28 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1117 : :
1118 : 28 : ret = VALENT_CHANNEL_GET_CLASS (channel)->download (channel,
1119 : : packet,
1120 : : cancellable,
1121 : : error);
1122 : :
1123 : 28 : VALENT_RETURN (ret);
1124 : : }
1125 : :
1126 : : /**
1127 : : * valent_channel_download_async: (virtual download_async)
1128 : : * @channel: a `ValentChannel`
1129 : : * @packet: a KDE Connect packet
1130 : : * @cancellable: (nullable): a `GCancellable`
1131 : : * @callback: (scope async): a `GAsyncReadyCallback`
1132 : : * @user_data: user supplied data
1133 : : *
1134 : : * Open an auxiliary connection, usually to download data.
1135 : : *
1136 : : * This is a non-blocking variant of [method@Valent.Channel.download]. Call
1137 : : * [method@Valent.Channel.download_finish] to get the result.
1138 : : *
1139 : : * The default implementation of this method invokes
1140 : : * [vfunc@Valent.Channel.download] in a thread.
1141 : : *
1142 : : * Since: 1.0
1143 : : */
1144 : : void
1145 : 1 : valent_channel_download_async (ValentChannel *channel,
1146 : : JsonNode *packet,
1147 : : GCancellable *cancellable,
1148 : : GAsyncReadyCallback callback,
1149 : : gpointer user_data)
1150 : : {
1151 : 1 : VALENT_ENTRY;
1152 : :
1153 [ + - ]: 1 : g_return_if_fail (VALENT_IS_CHANNEL (channel));
1154 [ - + ]: 1 : g_return_if_fail (VALENT_IS_PACKET (packet));
1155 [ - + - - : 1 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
1156 : :
1157 : 1 : VALENT_CHANNEL_GET_CLASS (channel)->download_async (channel,
1158 : : packet,
1159 : : cancellable,
1160 : : callback,
1161 : : user_data);
1162 : :
1163 : 1 : VALENT_EXIT;
1164 : : }
1165 : :
1166 : : /**
1167 : : * valent_channel_download_finish: (virtual download_finish)
1168 : : * @channel: a `ValentChannel`
1169 : : * @result: a `GAsyncResult`
1170 : : * @error: (nullable): a `GError`
1171 : : *
1172 : : * Finish an operation started with [method@Valent.Channel.download_async].
1173 : : *
1174 : : * Returns: (transfer full) (nullable): a `GIOStream`
1175 : : *
1176 : : * Since: 1.0
1177 : : */
1178 : : GIOStream *
1179 : 1 : valent_channel_download_finish (ValentChannel *channel,
1180 : : GAsyncResult *result,
1181 : : GError **error)
1182 : : {
1183 : 1 : GIOStream *ret;
1184 : :
1185 : 1 : VALENT_ENTRY;
1186 : :
1187 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
1188 [ - + ]: 1 : g_return_val_if_fail (g_task_is_valid (result, channel), NULL);
1189 [ + - - + ]: 1 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1190 : :
1191 : 1 : ret = VALENT_CHANNEL_GET_CLASS (channel)->download_finish (channel,
1192 : : result,
1193 : : error);
1194 : :
1195 : 1 : VALENT_RETURN (ret);
1196 : : }
1197 : :
1198 : : /**
1199 : : * valent_channel_upload: (virtual upload)
1200 : : * @channel: a `ValentChannel`
1201 : : * @packet: a KDE Connect packet
1202 : : * @cancellable: (nullable): a `GCancellable`
1203 : : * @error: (nullable): a `GError`
1204 : : *
1205 : : * Accept an auxiliary connection, usually to upload data.
1206 : : *
1207 : : * Implementations should set the `payloadTransferInfo` field with information
1208 : : * the peer can use to open a connection and wait to accept that connection. In
1209 : : * most cases the remote device with expect the caller to write to the stream
1210 : : * and then close it when finished.
1211 : : *
1212 : : * For example, a TCP-based implementation could start listening on a port then
1213 : : * send the packet with that port in the `payloadTransferInfo` dictionary. When
1214 : : * a connection is accepted the caller can perform operations on it as required.
1215 : : *
1216 : : * Returns: (transfer full) (nullable): a `GIOStream`
1217 : : *
1218 : : * Since: 1.0
1219 : : */
1220 : : GIOStream *
1221 : 28 : valent_channel_upload (ValentChannel *channel,
1222 : : JsonNode *packet,
1223 : : GCancellable *cancellable,
1224 : : GError **error)
1225 : : {
1226 : 28 : GIOStream *ret;
1227 : :
1228 : 28 : VALENT_ENTRY;
1229 : :
1230 [ + - ]: 28 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
1231 [ - + ]: 28 : g_return_val_if_fail (VALENT_IS_PACKET (packet), NULL);
1232 [ + + + - : 28 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- + - - ]
1233 [ + - - + ]: 28 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1234 : :
1235 : 28 : ret = VALENT_CHANNEL_GET_CLASS (channel)->upload (channel,
1236 : : packet,
1237 : : cancellable,
1238 : : error);
1239 : :
1240 : 28 : VALENT_RETURN (ret);
1241 : : }
1242 : :
1243 : : /**
1244 : : * valent_channel_upload_async: (virtual upload_async)
1245 : : * @channel: a `ValentChannel`
1246 : : * @packet: a KDE Connect packet
1247 : : * @cancellable: (nullable): a `GCancellable`
1248 : : * @callback: (scope async): a `GAsyncReadyCallback`
1249 : : * @user_data: user supplied data
1250 : : *
1251 : : * Accept an auxiliary connection, usually to upload data.
1252 : : *
1253 : : * This is a non-blocking variant of [method@Valent.Channel.upload]. Call
1254 : : * [method@Valent.Channel.upload_finish] to get the result.
1255 : : *
1256 : : * The default implementation of this method invokes
1257 : : * [vfunc@Valent.Channel.upload] in a thread.
1258 : : *
1259 : : * Since: 1.0
1260 : : */
1261 : : void
1262 : 1 : valent_channel_upload_async (ValentChannel *channel,
1263 : : JsonNode *packet,
1264 : : GCancellable *cancellable,
1265 : : GAsyncReadyCallback callback,
1266 : : gpointer user_data)
1267 : : {
1268 : 1 : VALENT_ENTRY;
1269 : :
1270 [ + - ]: 1 : g_return_if_fail (VALENT_IS_CHANNEL (channel));
1271 [ - + ]: 1 : g_return_if_fail (VALENT_IS_PACKET (packet));
1272 [ - + - - : 1 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
1273 : :
1274 : 1 : VALENT_CHANNEL_GET_CLASS (channel)->upload_async (channel,
1275 : : packet,
1276 : : cancellable,
1277 : : callback,
1278 : : user_data);
1279 : :
1280 : 1 : VALENT_EXIT;
1281 : : }
1282 : :
1283 : : /**
1284 : : * valent_channel_upload_finish: (virtual upload_finish)
1285 : : * @channel: a `ValentChannel`
1286 : : * @result: a `GAsyncResult`
1287 : : * @error: (nullable): a `GError`
1288 : : *
1289 : : * Finish an operation started with [method@Valent.Channel.upload_async].
1290 : : *
1291 : : * Returns: (transfer full) (nullable): a `GIOStream`
1292 : : *
1293 : : * Since: 1.0
1294 : : */
1295 : : GIOStream *
1296 : 1 : valent_channel_upload_finish (ValentChannel *channel,
1297 : : GAsyncResult *result,
1298 : : GError **error)
1299 : : {
1300 : 1 : GIOStream *ret;
1301 : :
1302 : 1 : VALENT_ENTRY;
1303 : :
1304 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);
1305 [ - + ]: 1 : g_return_val_if_fail (g_task_is_valid (result, channel), NULL);
1306 [ + - - + ]: 1 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1307 : :
1308 : 1 : ret = VALENT_CHANNEL_GET_CLASS (channel)->upload_finish (channel,
1309 : : result,
1310 : : error);
1311 : :
1312 : 1 : VALENT_RETURN (ret);
1313 : : }
1314 : :
|