nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
||
3 | * Copyright © 2009 Codethink Limited |
||
4 | * |
||
5 | * This program is free software: you can redistribute it and/or modify |
||
6 | * it under the terms of the GNU Lesser General Public License as published |
||
7 | * by the Free Software Foundation; either version 2 of the licence or (at |
||
8 | * your option) any later version. |
||
9 | * |
||
10 | * See the included COPYING file for more information. |
||
11 | * |
||
12 | * Authors: Ryan Lortie <desrt@desrt.ca> |
||
13 | */ |
||
14 | |||
15 | #include "config.h" |
||
16 | |||
17 | #include "gunixconnection.h" |
||
18 | #include "gnetworking.h" |
||
19 | #include "gsocket.h" |
||
20 | #include "gsocketcontrolmessage.h" |
||
21 | #include "gunixcredentialsmessage.h" |
||
22 | #include "gunixfdmessage.h" |
||
23 | #include "glibintl.h" |
||
24 | |||
25 | #include <errno.h> |
||
26 | #include <string.h> |
||
27 | #include <unistd.h> |
||
28 | |||
29 | /** |
||
30 | * SECTION:gunixconnection |
||
31 | * @title: GUnixConnection |
||
32 | * @short_description: A UNIX domain GSocketConnection |
||
33 | * @include: gio/gunixconnection.h |
||
34 | * @see_also: #GSocketConnection. |
||
35 | * |
||
36 | * This is the subclass of #GSocketConnection that is created |
||
37 | * for UNIX domain sockets. |
||
38 | * |
||
39 | * It contains functions to do some of the UNIX socket specific |
||
40 | * functionality like passing file descriptors. |
||
41 | * |
||
42 | * Note that `<gio/gunixconnection.h>` belongs to the UNIX-specific |
||
43 | * GIO interfaces, thus you have to use the `gio-unix-2.0.pc` |
||
44 | * pkg-config file when using it. |
||
45 | * |
||
46 | * Since: 2.22 |
||
47 | */ |
||
48 | |||
49 | /** |
||
50 | * GUnixConnection: |
||
51 | * |
||
52 | * #GUnixConnection is an opaque data structure and can only be accessed |
||
53 | * using the following functions. |
||
54 | **/ |
||
55 | |||
56 | G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection, |
||
57 | G_TYPE_SOCKET_CONNECTION, |
||
58 | g_socket_connection_factory_register_type (g_define_type_id, |
||
59 | G_SOCKET_FAMILY_UNIX, |
||
60 | G_SOCKET_TYPE_STREAM, |
||
61 | G_SOCKET_PROTOCOL_DEFAULT); |
||
62 | ); |
||
63 | |||
64 | /** |
||
65 | * g_unix_connection_send_fd: |
||
66 | * @connection: a #GUnixConnection |
||
67 | * @fd: a file descriptor |
||
68 | * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. |
||
69 | * @error: (allow-none): #GError for error reporting, or %NULL to ignore. |
||
70 | * |
||
71 | * Passes a file descriptor to the receiving side of the |
||
72 | * connection. The receiving end has to call g_unix_connection_receive_fd() |
||
73 | * to accept the file descriptor. |
||
74 | * |
||
75 | * As well as sending the fd this also writes a single byte to the |
||
76 | * stream, as this is required for fd passing to work on some |
||
77 | * implementations. |
||
78 | * |
||
79 | * Returns: a %TRUE on success, %NULL on error. |
||
80 | * |
||
81 | * Since: 2.22 |
||
82 | */ |
||
83 | gboolean |
||
84 | g_unix_connection_send_fd (GUnixConnection *connection, |
||
85 | gint fd, |
||
86 | GCancellable *cancellable, |
||
87 | GError **error) |
||
88 | { |
||
89 | GSocketControlMessage *scm; |
||
90 | GSocket *socket; |
||
91 | |||
92 | g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE); |
||
93 | g_return_val_if_fail (fd >= 0, FALSE); |
||
94 | |||
95 | scm = g_unix_fd_message_new (); |
||
96 | |||
97 | if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error)) |
||
98 | { |
||
99 | g_object_unref (scm); |
||
100 | return FALSE; |
||
101 | } |
||
102 | |||
103 | g_object_get (connection, "socket", &socket, NULL); |
||
104 | if (g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, error) != 1) |
||
105 | /* XXX could it 'fail' with zero? */ |
||
106 | { |
||
107 | g_object_unref (socket); |
||
108 | g_object_unref (scm); |
||
109 | |||
110 | return FALSE; |
||
111 | } |
||
112 | |||
113 | g_object_unref (socket); |
||
114 | g_object_unref (scm); |
||
115 | |||
116 | return TRUE; |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * g_unix_connection_receive_fd: |
||
121 | * @connection: a #GUnixConnection |
||
122 | * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore |
||
123 | * @error: (allow-none): #GError for error reporting, or %NULL to ignore |
||
124 | * |
||
125 | * Receives a file descriptor from the sending end of the connection. |
||
126 | * The sending end has to call g_unix_connection_send_fd() for this |
||
127 | * to work. |
||
128 | * |
||
129 | * As well as reading the fd this also reads a single byte from the |
||
130 | * stream, as this is required for fd passing to work on some |
||
131 | * implementations. |
||
132 | * |
||
133 | * Returns: a file descriptor on success, -1 on error. |
||
134 | * |
||
135 | * Since: 2.22 |
||
136 | **/ |
||
137 | gint |
||
138 | g_unix_connection_receive_fd (GUnixConnection *connection, |
||
139 | GCancellable *cancellable, |
||
140 | GError **error) |
||
141 | { |
||
142 | GSocketControlMessage **scms; |
||
143 | gint *fds, nfd, fd, nscm; |
||
144 | GUnixFDMessage *fdmsg; |
||
145 | GSocket *socket; |
||
146 | |||
147 | g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1); |
||
148 | |||
149 | g_object_get (connection, "socket", &socket, NULL); |
||
150 | if (g_socket_receive_message (socket, NULL, NULL, 0, |
||
151 | &scms, &nscm, NULL, cancellable, error) != 1) |
||
152 | /* XXX it _could_ 'fail' with zero. */ |
||
153 | { |
||
154 | g_object_unref (socket); |
||
155 | |||
156 | return -1; |
||
157 | } |
||
158 | |||
159 | g_object_unref (socket); |
||
160 | |||
161 | if (nscm != 1) |
||
162 | { |
||
163 | gint i; |
||
164 | |||
165 | g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
||
166 | ngettext("Expecting 1 control message, got %d", |
||
167 | "Expecting 1 control message, got %d", |
||
168 | nscm), |
||
169 | nscm); |
||
170 | |||
171 | for (i = 0; i < nscm; i++) |
||
172 | g_object_unref (scms[i]); |
||
173 | |||
174 | g_free (scms); |
||
175 | |||
176 | return -1; |
||
177 | } |
||
178 | |||
179 | if (!G_IS_UNIX_FD_MESSAGE (scms[0])) |
||
180 | { |
||
181 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
||
182 | _("Unexpected type of ancillary data")); |
||
183 | g_object_unref (scms[0]); |
||
184 | g_free (scms); |
||
185 | |||
186 | return -1; |
||
187 | } |
||
188 | |||
189 | fdmsg = G_UNIX_FD_MESSAGE (scms[0]); |
||
190 | g_free (scms); |
||
191 | |||
192 | fds = g_unix_fd_message_steal_fds (fdmsg, &nfd); |
||
193 | g_object_unref (fdmsg); |
||
194 | |||
195 | if (nfd != 1) |
||
196 | { |
||
197 | gint i; |
||
198 | |||
199 | g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
||
200 | ngettext("Expecting one fd, but got %d\n", |
||
201 | "Expecting one fd, but got %d\n", |
||
202 | nfd), |
||
203 | nfd); |
||
204 | |||
205 | for (i = 0; i < nfd; i++) |
||
206 | close (fds[i]); |
||
207 | |||
208 | g_free (fds); |
||
209 | |||
210 | return -1; |
||
211 | } |
||
212 | |||
213 | fd = *fds; |
||
214 | g_free (fds); |
||
215 | |||
216 | if (fd < 0) |
||
217 | { |
||
218 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
||
219 | _("Received invalid fd")); |
||
220 | fd = -1; |
||
221 | } |
||
222 | |||
223 | return fd; |
||
224 | } |
||
225 | |||
226 | static void |
||
227 | g_unix_connection_init (GUnixConnection *connection) |
||
228 | { |
||
229 | } |
||
230 | |||
231 | static void |
||
232 | g_unix_connection_class_init (GUnixConnectionClass *class) |
||
233 | { |
||
234 | } |
||
235 | |||
236 | /* TODO: Other stuff we might want to add are: |
||
237 | void g_unix_connection_send_fd_async (GUnixConnection *connection, |
||
238 | gint fd, |
||
239 | gboolean close, |
||
240 | gint io_priority, |
||
241 | GAsyncReadyCallback callback, |
||
242 | gpointer user_data); |
||
243 | gboolean g_unix_connection_send_fd_finish (GUnixConnection *connection, |
||
244 | GError **error); |
||
245 | |||
246 | gboolean g_unix_connection_send_fds (GUnixConnection *connection, |
||
247 | gint *fds, |
||
248 | gint nfds, |
||
249 | GError **error); |
||
250 | void g_unix_connection_send_fds_async (GUnixConnection *connection, |
||
251 | gint *fds, |
||
252 | gint nfds, |
||
253 | gint io_priority, |
||
254 | GAsyncReadyCallback callback, |
||
255 | gpointer user_data); |
||
256 | gboolean g_unix_connection_send_fds_finish (GUnixConnection *connection, |
||
257 | GError **error); |
||
258 | |||
259 | void g_unix_connection_receive_fd_async (GUnixConnection *connection, |
||
260 | gint io_priority, |
||
261 | GAsyncReadyCallback callback, |
||
262 | gpointer user_data); |
||
263 | gint g_unix_connection_receive_fd_finish (GUnixConnection *connection, |
||
264 | GError **error); |
||
265 | |||
266 | |||
267 | gboolean g_unix_connection_send_fake_credentials (GUnixConnection *connection, |
||
268 | guint64 pid, |
||
269 | guint64 uid, |
||
270 | guint64 gid, |
||
271 | GError **error); |
||
272 | void g_unix_connection_send_fake_credentials_async (GUnixConnection *connection, |
||
273 | guint64 pid, |
||
274 | guint64 uid, |
||
275 | guint64 gid, |
||
276 | gint io_priority, |
||
277 | GAsyncReadyCallback callback, |
||
278 | gpointer user_data); |
||
279 | gboolean g_unix_connection_send_fake_credentials_finish (GUnixConnection *connection, |
||
280 | GError **error); |
||
281 | |||
282 | gboolean g_unix_connection_create_pair (GUnixConnection **one, |
||
283 | GUnixConnection **two, |
||
284 | GError **error); |
||
285 | */ |
||
286 | |||
287 | |||
288 | /** |
||
289 | * g_unix_connection_send_credentials: |
||
290 | * @connection: A #GUnixConnection. |
||
291 | * @cancellable: (allow-none): A #GCancellable or %NULL. |
||
292 | * @error: Return location for error or %NULL. |
||
293 | * |
||
294 | * Passes the credentials of the current user the receiving side |
||
295 | * of the connection. The receiving end has to call |
||
296 | * g_unix_connection_receive_credentials() (or similar) to accept the |
||
297 | * credentials. |
||
298 | * |
||
299 | * As well as sending the credentials this also writes a single NUL |
||
300 | * byte to the stream, as this is required for credentials passing to |
||
301 | * work on some implementations. |
||
302 | * |
||
303 | * Other ways to exchange credentials with a foreign peer includes the |
||
304 | * #GUnixCredentialsMessage type and g_socket_get_credentials() function. |
||
305 | * |
||
306 | * Returns: %TRUE on success, %FALSE if @error is set. |
||
307 | * |
||
308 | * Since: 2.26 |
||
309 | */ |
||
310 | gboolean |
||
311 | g_unix_connection_send_credentials (GUnixConnection *connection, |
||
312 | GCancellable *cancellable, |
||
313 | GError **error) |
||
314 | { |
||
315 | GCredentials *credentials; |
||
316 | GSocketControlMessage *scm; |
||
317 | GSocket *socket; |
||
318 | gboolean ret; |
||
319 | GOutputVector vector; |
||
320 | guchar nul_byte[1] = {'\0'}; |
||
321 | gint num_messages; |
||
322 | |||
323 | g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE); |
||
324 | g_return_val_if_fail (error == NULL || *error == NULL, FALSE); |
||
325 | |||
326 | ret = FALSE; |
||
327 | |||
328 | credentials = g_credentials_new (); |
||
329 | |||
330 | vector.buffer = &nul_byte; |
||
331 | vector.size = 1; |
||
332 | |||
333 | if (g_unix_credentials_message_is_supported ()) |
||
334 | { |
||
335 | scm = g_unix_credentials_message_new_with_credentials (credentials); |
||
336 | num_messages = 1; |
||
337 | } |
||
338 | else |
||
339 | { |
||
340 | scm = NULL; |
||
341 | num_messages = 0; |
||
342 | } |
||
343 | |||
344 | g_object_get (connection, "socket", &socket, NULL); |
||
345 | if (g_socket_send_message (socket, |
||
346 | NULL, /* address */ |
||
347 | &vector, |
||
348 | 1, |
||
349 | &scm, |
||
350 | num_messages, |
||
351 | G_SOCKET_MSG_NONE, |
||
352 | cancellable, |
||
353 | error) != 1) |
||
354 | { |
||
355 | g_prefix_error (error, _("Error sending credentials: ")); |
||
356 | goto out; |
||
357 | } |
||
358 | |||
359 | ret = TRUE; |
||
360 | |||
361 | out: |
||
362 | g_object_unref (socket); |
||
363 | if (scm != NULL) |
||
364 | g_object_unref (scm); |
||
365 | g_object_unref (credentials); |
||
366 | return ret; |
||
367 | } |
||
368 | |||
369 | static void |
||
370 | send_credentials_async_thread (GTask *task, |
||
371 | gpointer source_object, |
||
372 | gpointer task_data, |
||
373 | GCancellable *cancellable) |
||
374 | { |
||
375 | GError *error = NULL; |
||
376 | |||
377 | if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object), |
||
378 | cancellable, |
||
379 | &error)) |
||
380 | g_task_return_boolean (task, TRUE); |
||
381 | else |
||
382 | g_task_return_error (task, error); |
||
383 | g_object_unref (task); |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * g_unix_connection_send_credentials_async: |
||
388 | * @connection: A #GUnixConnection. |
||
389 | * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. |
||
390 | * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied |
||
391 | * @user_data: (closure): the data to pass to callback function |
||
392 | * |
||
393 | * Asynchronously send credentials. |
||
394 | * |
||
395 | * For more details, see g_unix_connection_send_credentials() which is |
||
396 | * the synchronous version of this call. |
||
397 | * |
||
398 | * When the operation is finished, @callback will be called. You can then call |
||
399 | * g_unix_connection_send_credentials_finish() to get the result of the operation. |
||
400 | * |
||
401 | * Since: 2.32 |
||
402 | **/ |
||
403 | void |
||
404 | g_unix_connection_send_credentials_async (GUnixConnection *connection, |
||
405 | GCancellable *cancellable, |
||
406 | GAsyncReadyCallback callback, |
||
407 | gpointer user_data) |
||
408 | { |
||
409 | GTask *task; |
||
410 | |||
411 | task = g_task_new (connection, cancellable, callback, user_data); |
||
412 | |||
413 | g_task_run_in_thread (task, send_credentials_async_thread); |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * g_unix_connection_send_credentials_finish: |
||
418 | * @connection: A #GUnixConnection. |
||
419 | * @result: a #GAsyncResult. |
||
420 | * @error: a #GError, or %NULL |
||
421 | * |
||
422 | * Finishes an asynchronous send credentials operation started with |
||
423 | * g_unix_connection_send_credentials_async(). |
||
424 | * |
||
425 | * Returns: %TRUE if the operation was successful, otherwise %FALSE. |
||
426 | * |
||
427 | * Since: 2.32 |
||
428 | **/ |
||
429 | gboolean |
||
430 | g_unix_connection_send_credentials_finish (GUnixConnection *connection, |
||
431 | GAsyncResult *result, |
||
432 | GError **error) |
||
433 | { |
||
434 | g_return_val_if_fail (g_task_is_valid (result, connection), FALSE); |
||
435 | |||
436 | return g_task_propagate_boolean (G_TASK (result), error); |
||
437 | } |
||
438 | |||
439 | /** |
||
440 | * g_unix_connection_receive_credentials: |
||
441 | * @connection: A #GUnixConnection. |
||
442 | * @cancellable: (allow-none): A #GCancellable or %NULL. |
||
443 | * @error: Return location for error or %NULL. |
||
444 | * |
||
445 | * Receives credentials from the sending end of the connection. The |
||
446 | * sending end has to call g_unix_connection_send_credentials() (or |
||
447 | * similar) for this to work. |
||
448 | * |
||
449 | * As well as reading the credentials this also reads (and discards) a |
||
450 | * single byte from the stream, as this is required for credentials |
||
451 | * passing to work on some implementations. |
||
452 | * |
||
453 | * Other ways to exchange credentials with a foreign peer includes the |
||
454 | * #GUnixCredentialsMessage type and g_socket_get_credentials() function. |
||
455 | * |
||
456 | * Returns: (transfer full): Received credentials on success (free with |
||
457 | * g_object_unref()), %NULL if @error is set. |
||
458 | * |
||
459 | * Since: 2.26 |
||
460 | */ |
||
461 | GCredentials * |
||
462 | g_unix_connection_receive_credentials (GUnixConnection *connection, |
||
463 | GCancellable *cancellable, |
||
464 | GError **error) |
||
465 | { |
||
466 | GCredentials *ret; |
||
467 | GSocketControlMessage **scms; |
||
468 | gint nscm; |
||
469 | GSocket *socket; |
||
470 | gint n; |
||
471 | gssize num_bytes_read; |
||
472 | #ifdef __linux__ |
||
473 | gboolean turn_off_so_passcreds; |
||
474 | #endif |
||
475 | |||
476 | g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), NULL); |
||
477 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
||
478 | |||
479 | ret = NULL; |
||
480 | scms = NULL; |
||
481 | |||
482 | g_object_get (connection, "socket", &socket, NULL); |
||
483 | |||
484 | /* On Linux, we need to turn on SO_PASSCRED if it isn't enabled |
||
485 | * already. We also need to turn it off when we're done. See |
||
486 | * #617483 for more discussion. |
||
487 | */ |
||
488 | #ifdef __linux__ |
||
489 | { |
||
490 | gint opt_val; |
||
491 | |||
492 | turn_off_so_passcreds = FALSE; |
||
493 | opt_val = 0; |
||
494 | if (!g_socket_get_option (socket, |
||
495 | SOL_SOCKET, |
||
496 | SO_PASSCRED, |
||
497 | &opt_val, |
||
498 | NULL)) |
||
499 | { |
||
500 | g_set_error (error, |
||
501 | G_IO_ERROR, |
||
502 | g_io_error_from_errno (errno), |
||
503 | _("Error checking if SO_PASSCRED is enabled for socket: %s"), |
||
504 | strerror (errno)); |
||
505 | goto out; |
||
506 | } |
||
507 | if (opt_val == 0) |
||
508 | { |
||
509 | if (!g_socket_set_option (socket, |
||
510 | SOL_SOCKET, |
||
511 | SO_PASSCRED, |
||
512 | TRUE, |
||
513 | NULL)) |
||
514 | { |
||
515 | g_set_error (error, |
||
516 | G_IO_ERROR, |
||
517 | g_io_error_from_errno (errno), |
||
518 | _("Error enabling SO_PASSCRED: %s"), |
||
519 | strerror (errno)); |
||
520 | goto out; |
||
521 | } |
||
522 | turn_off_so_passcreds = TRUE; |
||
523 | } |
||
524 | } |
||
525 | #endif |
||
526 | |||
527 | g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE); |
||
528 | num_bytes_read = g_socket_receive_message (socket, |
||
529 | NULL, /* GSocketAddress **address */ |
||
530 | NULL, |
||
531 | 0, |
||
532 | &scms, |
||
533 | &nscm, |
||
534 | NULL, |
||
535 | cancellable, |
||
536 | error); |
||
537 | if (num_bytes_read != 1) |
||
538 | { |
||
539 | /* Handle situation where g_socket_receive_message() returns |
||
540 | * 0 bytes and not setting @error |
||
541 | */ |
||
542 | if (num_bytes_read == 0 && error != NULL && *error == NULL) |
||
543 | { |
||
544 | g_set_error_literal (error, |
||
545 | G_IO_ERROR, |
||
546 | G_IO_ERROR_FAILED, |
||
547 | _("Expecting to read a single byte for receiving credentials but read zero bytes")); |
||
548 | } |
||
549 | goto out; |
||
550 | } |
||
551 | |||
552 | if (g_unix_credentials_message_is_supported () && |
||
553 | /* Fall back on get_credentials if the other side didn't send the credentials */ |
||
554 | nscm > 0) |
||
555 | { |
||
556 | if (nscm != 1) |
||
557 | { |
||
558 | g_set_error (error, |
||
559 | G_IO_ERROR, |
||
560 | G_IO_ERROR_FAILED, |
||
561 | ngettext("Expecting 1 control message, got %d", |
||
562 | "Expecting 1 control message, got %d", |
||
563 | nscm), |
||
564 | nscm); |
||
565 | goto out; |
||
566 | } |
||
567 | |||
568 | if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0])) |
||
569 | { |
||
570 | g_set_error_literal (error, |
||
571 | G_IO_ERROR, |
||
572 | G_IO_ERROR_FAILED, |
||
573 | _("Unexpected type of ancillary data")); |
||
574 | goto out; |
||
575 | } |
||
576 | |||
577 | ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0])); |
||
578 | g_object_ref (ret); |
||
579 | } |
||
580 | else |
||
581 | { |
||
582 | if (nscm != 0) |
||
583 | { |
||
584 | g_set_error (error, |
||
585 | G_IO_ERROR, |
||
586 | G_IO_ERROR_FAILED, |
||
587 | _("Not expecting control message, but got %d"), |
||
588 | nscm); |
||
589 | goto out; |
||
590 | } |
||
591 | else |
||
592 | { |
||
593 | ret = g_socket_get_credentials (socket, error); |
||
594 | } |
||
595 | } |
||
596 | |||
597 | out: |
||
598 | |||
599 | #ifdef __linux__ |
||
600 | if (turn_off_so_passcreds) |
||
601 | { |
||
602 | if (!g_socket_set_option (socket, |
||
603 | SOL_SOCKET, |
||
604 | SO_PASSCRED, |
||
605 | FALSE, |
||
606 | NULL)) |
||
607 | { |
||
608 | g_set_error (error, |
||
609 | G_IO_ERROR, |
||
610 | g_io_error_from_errno (errno), |
||
611 | _("Error while disabling SO_PASSCRED: %s"), |
||
612 | strerror (errno)); |
||
613 | goto out; |
||
614 | } |
||
615 | } |
||
616 | #endif |
||
617 | |||
618 | if (scms != NULL) |
||
619 | { |
||
620 | for (n = 0; n < nscm; n++) |
||
621 | g_object_unref (scms[n]); |
||
622 | g_free (scms); |
||
623 | } |
||
624 | g_object_unref (socket); |
||
625 | return ret; |
||
626 | } |
||
627 | |||
628 | static void |
||
629 | receive_credentials_async_thread (GTask *task, |
||
630 | gpointer source_object, |
||
631 | gpointer task_data, |
||
632 | GCancellable *cancellable) |
||
633 | { |
||
634 | GCredentials *creds; |
||
635 | GError *error = NULL; |
||
636 | |||
637 | creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object), |
||
638 | cancellable, |
||
639 | &error); |
||
640 | if (creds) |
||
641 | g_task_return_pointer (task, creds, g_object_unref); |
||
642 | else |
||
643 | g_task_return_error (task, error); |
||
644 | g_object_unref (task); |
||
645 | } |
||
646 | |||
647 | /** |
||
648 | * g_unix_connection_receive_credentials_async: |
||
649 | * @connection: A #GUnixConnection. |
||
650 | * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. |
||
651 | * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied |
||
652 | * @user_data: (closure): the data to pass to callback function |
||
653 | * |
||
654 | * Asynchronously receive credentials. |
||
655 | * |
||
656 | * For more details, see g_unix_connection_receive_credentials() which is |
||
657 | * the synchronous version of this call. |
||
658 | * |
||
659 | * When the operation is finished, @callback will be called. You can then call |
||
660 | * g_unix_connection_receive_credentials_finish() to get the result of the operation. |
||
661 | * |
||
662 | * Since: 2.32 |
||
663 | **/ |
||
664 | void |
||
665 | g_unix_connection_receive_credentials_async (GUnixConnection *connection, |
||
666 | GCancellable *cancellable, |
||
667 | GAsyncReadyCallback callback, |
||
668 | gpointer user_data) |
||
669 | { |
||
670 | GTask *task; |
||
671 | |||
672 | task = g_task_new (connection, cancellable, callback, user_data); |
||
673 | |||
674 | g_task_run_in_thread (task, receive_credentials_async_thread); |
||
675 | } |
||
676 | |||
677 | /** |
||
678 | * g_unix_connection_receive_credentials_finish: |
||
679 | * @connection: A #GUnixConnection. |
||
680 | * @result: a #GAsyncResult. |
||
681 | * @error: a #GError, or %NULL |
||
682 | * |
||
683 | * Finishes an asynchronous receive credentials operation started with |
||
684 | * g_unix_connection_receive_credentials_async(). |
||
685 | * |
||
686 | * Returns: (transfer full): a #GCredentials, or %NULL on error. |
||
687 | * Free the returned object with g_object_unref(). |
||
688 | * |
||
689 | * Since: 2.32 |
||
690 | **/ |
||
691 | GCredentials * |
||
692 | g_unix_connection_receive_credentials_finish (GUnixConnection *connection, |
||
693 | GAsyncResult *result, |
||
694 | GError **error) |
||
695 | { |
||
696 | g_return_val_if_fail (g_task_is_valid (result, connection), NULL); |
||
697 | |||
698 | return g_task_propagate_pointer (G_TASK (result), error); |
||
699 | } |