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