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