X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgunixconnection.c;h=b5da60a4edeb082469e5adc99d0a0a9e606f3a25;hb=33b9935efc82f8cc4747dfea2743129dfc418d19;hp=3921c92d24ad746d15eb737cc79238e06accf541;hpb=6223341cacc7dfa34a8d60ec1b4828382dee6d07;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gunixconnection.c b/gio/gunixconnection.c index 3921c92..b5da60a 100644 --- a/gio/gunixconnection.c +++ b/gio/gunixconnection.c @@ -13,11 +13,21 @@ */ #include "config.h" + #include "gunixconnection.h" +#include "gnetworking.h" +#include "gsocket.h" +#include "gsocketcontrolmessage.h" +#include "gunixcredentialsmessage.h" +#include "gunixfdmessage.h" #include "glibintl.h" +#include +#include +#include + /** - * SECTION: gunixconnection + * SECTION:gunixconnection * @title: GUnixConnection * @short_description: A UNIX domain GSocketConnection * @include: gio/gunixconnection.h @@ -29,28 +39,13 @@ * It contains functions to do some of the UNIX socket specific * functionality like passing file descriptors. * - * Note that <gio/gunixconnection.h> belongs to - * the UNIX-specific GIO interfaces, thus you have to use the - * gio-unix-2.0.pc pkg-config file when using it. + * Note that `` belongs to the UNIX-specific + * GIO interfaces, thus you have to use the `gio-unix-2.0.pc` + * pkg-config file when using it. * * Since: 2.22 */ -#include -#include -#include -#include - -#ifdef __linux__ -/* for getsockopt() and setsockopt() */ -#include /* See NOTES */ -#include -#include -#include -#endif - -#include "gioalias.h" - G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection, G_TYPE_SOCKET_CONNECTION, g_socket_connection_factory_register_type (g_define_type_id, @@ -63,11 +58,11 @@ G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection, * g_unix_connection_send_fd: * @connection: a #GUnixConnection * @fd: a file descriptor - * @cancellable: optional #GCancellable object, %NULL to ignore. - * @error: #GError for error reporting, or %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @error: (allow-none): #GError for error reporting, or %NULL to ignore. * - * Passes a file descriptor to the recieving side of the - * connection. The recieving end has to call g_unix_connection_receive_fd() + * Passes a file descriptor to the receiving side of the + * connection. The receiving end has to call g_unix_connection_receive_fd() * to accept the file descriptor. * * As well as sending the fd this also writes a single byte to the @@ -117,8 +112,8 @@ g_unix_connection_send_fd (GUnixConnection *connection, /** * g_unix_connection_receive_fd: * @connection: a #GUnixConnection - * @cancellable: optional #GCancellable object, %NULL to ignore - * @error: #GError for error reporting, or %NULL to ignore + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore + * @error: (allow-none): #GError for error reporting, or %NULL to ignore * * Receives a file descriptor from the sending end of the connection. * The sending end has to call g_unix_connection_send_fd() for this @@ -131,7 +126,7 @@ g_unix_connection_send_fd (GUnixConnection *connection, * Returns: a file descriptor on success, -1 on error. * * Since: 2.22 - */ + **/ gint g_unix_connection_receive_fd (GUnixConnection *connection, GCancellable *cancellable, @@ -161,7 +156,10 @@ g_unix_connection_receive_fd (GUnixConnection *connection, gint i; g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - _("Expecting 1 control message, got %d"), nscm); + ngettext("Expecting 1 control message, got %d", + "Expecting 1 control message, got %d", + nscm), + nscm); for (i = 0; i < nscm; i++) g_object_unref (scms[i]); @@ -192,7 +190,10 @@ g_unix_connection_receive_fd (GUnixConnection *connection, gint i; g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - _("Expecting one fd, but got %d\n"), nfd); + ngettext("Expecting one fd, but got %d\n", + "Expecting one fd, but got %d\n", + nfd), + nfd); for (i = 0; i < nfd; i++) close (fds[i]); @@ -256,15 +257,6 @@ gint g_unix_connection_receive_fd_finish (GUnixCo GError **error); -gboolean g_unix_connection_send_credentials (GUnixConnection *connection, - GError **error); -void g_unix_connection_send_credentials_async (GUnixConnection *connection, - gint io_priority, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean g_unix_connection_send_credentials_finish (GUnixConnection *connection, - GError **error); - gboolean g_unix_connection_send_fake_credentials (GUnixConnection *connection, guint64 pid, guint64 uid, @@ -280,21 +272,6 @@ void g_unix_connection_send_fake_credentials_async (GUnixCo gboolean g_unix_connection_send_fake_credentials_finish (GUnixConnection *connection, GError **error); -gboolean g_unix_connection_receive_credentials (GUnixConnection *connection, - guint64 *pid, - guint64 *uid, - guint64 *gid, - GError **error); -void g_unix_connection_receive_credentials_async (GUnixConnection *connection, - gint io_priority, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean g_unix_connection_receive_credentials_finish (GUnixConnection *connection, - guint64 *pid, - guint64 *uid, - guint64 *gid, - GError **error); - gboolean g_unix_connection_create_pair (GUnixConnection **one, GUnixConnection **two, GError **error); @@ -304,11 +281,11 @@ gboolean g_unix_connection_create_pair (GUnixCo /** * g_unix_connection_send_credentials: * @connection: A #GUnixConnection. - * @cancellable: A #GCancellable or %NULL. + * @cancellable: (allow-none): A #GCancellable or %NULL. * @error: Return location for error or %NULL. * * Passes the credentials of the current user the receiving side - * of the connection. The recieving end has to call + * of the connection. The receiving end has to call * g_unix_connection_receive_credentials() (or similar) to accept the * credentials. * @@ -316,7 +293,8 @@ gboolean g_unix_connection_create_pair (GUnixCo * byte to the stream, as this is required for credentials passing to * work on some implementations. * - * Note that this function only works on Linux, currently. + * Other ways to exchange credentials with a foreign peer includes the + * #GUnixCredentialsMessage type and g_socket_get_credentials() function. * * Returns: %TRUE on success, %FALSE if @error is set. * @@ -333,6 +311,7 @@ g_unix_connection_send_credentials (GUnixConnection *connection, gboolean ret; GOutputVector vector; guchar nul_byte[1] = {'\0'}; + gint num_messages; g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -343,14 +322,25 @@ g_unix_connection_send_credentials (GUnixConnection *connection, vector.buffer = &nul_byte; vector.size = 1; - scm = g_unix_credentials_message_new_with_credentials (credentials); + + if (g_unix_credentials_message_is_supported ()) + { + scm = g_unix_credentials_message_new_with_credentials (credentials); + num_messages = 1; + } + else + { + scm = NULL; + num_messages = 0; + } + g_object_get (connection, "socket", &socket, NULL); if (g_socket_send_message (socket, NULL, /* address */ &vector, 1, &scm, - 1, + num_messages, G_SOCKET_MSG_NONE, cancellable, error) != 1) @@ -363,15 +353,86 @@ g_unix_connection_send_credentials (GUnixConnection *connection, out: g_object_unref (socket); - g_object_unref (scm); + if (scm != NULL) + g_object_unref (scm); g_object_unref (credentials); return ret; } +static void +send_credentials_async_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GError *error = NULL; + + if (g_unix_connection_send_credentials (G_UNIX_CONNECTION (source_object), + cancellable, + &error)) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); + g_object_unref (task); +} + +/** + * g_unix_connection_send_credentials_async: + * @connection: A #GUnixConnection. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously send credentials. + * + * For more details, see g_unix_connection_send_credentials() which is + * the synchronous version of this call. + * + * When the operation is finished, @callback will be called. You can then call + * g_unix_connection_send_credentials_finish() to get the result of the operation. + * + * Since: 2.32 + **/ +void +g_unix_connection_send_credentials_async (GUnixConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (connection, cancellable, callback, user_data); + + g_task_run_in_thread (task, send_credentials_async_thread); +} + +/** + * g_unix_connection_send_credentials_finish: + * @connection: A #GUnixConnection. + * @result: a #GAsyncResult. + * @error: a #GError, or %NULL + * + * Finishes an asynchronous send credentials operation started with + * g_unix_connection_send_credentials_async(). + * + * Returns: %TRUE if the operation was successful, otherwise %FALSE. + * + * Since: 2.32 + **/ +gboolean +g_unix_connection_send_credentials_finish (GUnixConnection *connection, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, connection), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + /** * g_unix_connection_receive_credentials: * @connection: A #GUnixConnection. - * @cancellable: A #GCancellable or %NULL. + * @cancellable: (allow-none): A #GCancellable or %NULL. * @error: Return location for error or %NULL. * * Receives credentials from the sending end of the connection. The @@ -382,7 +443,10 @@ g_unix_connection_send_credentials (GUnixConnection *connection, * single byte from the stream, as this is required for credentials * passing to work on some implementations. * - * Returns: Received credentials on success (free with + * Other ways to exchange credentials with a foreign peer includes the + * #GUnixCredentialsMessage type and g_socket_get_credentials() function. + * + * Returns: (transfer full): Received credentials on success (free with * g_object_unref()), %NULL if @error is set. * * Since: 2.26 @@ -397,7 +461,6 @@ g_unix_connection_receive_credentials (GUnixConnection *connection, gint nscm; GSocket *socket; gint n; - volatile GType credentials_message_gtype; gssize num_bytes_read; #ifdef __linux__ gboolean turn_off_so_passcreds; @@ -418,16 +481,14 @@ g_unix_connection_receive_credentials (GUnixConnection *connection, #ifdef __linux__ { gint opt_val; - socklen_t opt_len; turn_off_so_passcreds = FALSE; opt_val = 0; - opt_len = sizeof (gint); - if (getsockopt (g_socket_get_fd (socket), - SOL_SOCKET, - SO_PASSCRED, - &opt_val, - &opt_len) != 0) + if (!g_socket_get_option (socket, + SOL_SOCKET, + SO_PASSCRED, + &opt_val, + NULL)) { g_set_error (error, G_IO_ERROR, @@ -436,24 +497,13 @@ g_unix_connection_receive_credentials (GUnixConnection *connection, strerror (errno)); goto out; } - if (opt_len != sizeof (gint)) - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - _("Unexpected option length while checking if SO_PASSCRED is enabled for socket. " - "Expected %d bytes, got %d"), - (gint) sizeof (gint), (gint) opt_len); - goto out; - } if (opt_val == 0) { - opt_val = 1; - if (setsockopt (g_socket_get_fd (socket), - SOL_SOCKET, - SO_PASSCRED, - &opt_val, - sizeof opt_val) != 0) + if (!g_socket_set_option (socket, + SOL_SOCKET, + SO_PASSCRED, + TRUE, + NULL)) { g_set_error (error, G_IO_ERROR, @@ -467,8 +517,7 @@ g_unix_connection_receive_credentials (GUnixConnection *connection, } #endif - /* ensure the type of GUnixCredentialsMessage has been registered with the type system */ - credentials_message_gtype = G_TYPE_UNIX_CREDENTIALS_MESSAGE; + g_type_ensure (G_TYPE_UNIX_CREDENTIALS_MESSAGE); num_bytes_read = g_socket_receive_message (socket, NULL, /* GSocketAddress **address */ NULL, @@ -493,40 +542,61 @@ g_unix_connection_receive_credentials (GUnixConnection *connection, goto out; } - if (nscm != 1) + if (g_unix_credentials_message_is_supported () && + /* Fall back on get_credentials if the other side didn't send the credentials */ + nscm > 0) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - _("Expecting 1 control message, got %d"), - nscm); - goto out; - } + if (nscm != 1) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + ngettext("Expecting 1 control message, got %d", + "Expecting 1 control message, got %d", + nscm), + nscm); + goto out; + } - if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0])) + if (!G_IS_UNIX_CREDENTIALS_MESSAGE (scms[0])) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Unexpected type of ancillary data")); + goto out; + } + + ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0])); + g_object_ref (ret); + } + else { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - _("Unexpected type of ancillary data")); - goto out; + if (nscm != 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + _("Not expecting control message, but got %d"), + nscm); + goto out; + } + else + { + ret = g_socket_get_credentials (socket, error); + } } - ret = g_unix_credentials_message_get_credentials (G_UNIX_CREDENTIALS_MESSAGE (scms[0])); - g_object_ref (ret); - out: #ifdef __linux__ if (turn_off_so_passcreds) { - gint opt_val; - opt_val = 0; - if (setsockopt (g_socket_get_fd (socket), - SOL_SOCKET, - SO_PASSCRED, - &opt_val, - sizeof opt_val) != 0) + if (!g_socket_set_option (socket, + SOL_SOCKET, + SO_PASSCRED, + FALSE, + NULL)) { g_set_error (error, G_IO_ERROR, @@ -548,5 +618,75 @@ g_unix_connection_receive_credentials (GUnixConnection *connection, return ret; } -#define __G_UNIX_CONNECTION_C__ -#include "gioaliasdef.c" +static void +receive_credentials_async_thread (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GCredentials *creds; + GError *error = NULL; + + creds = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (source_object), + cancellable, + &error); + if (creds) + g_task_return_pointer (task, creds, g_object_unref); + else + g_task_return_error (task, error); + g_object_unref (task); +} + +/** + * g_unix_connection_receive_credentials_async: + * @connection: A #GUnixConnection. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously receive credentials. + * + * For more details, see g_unix_connection_receive_credentials() which is + * the synchronous version of this call. + * + * When the operation is finished, @callback will be called. You can then call + * g_unix_connection_receive_credentials_finish() to get the result of the operation. + * + * Since: 2.32 + **/ +void +g_unix_connection_receive_credentials_async (GUnixConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (connection, cancellable, callback, user_data); + + g_task_run_in_thread (task, receive_credentials_async_thread); +} + +/** + * g_unix_connection_receive_credentials_finish: + * @connection: A #GUnixConnection. + * @result: a #GAsyncResult. + * @error: a #GError, or %NULL + * + * Finishes an asynchronous receive credentials operation started with + * g_unix_connection_receive_credentials_async(). + * + * Returns: (transfer full): a #GCredentials, or %NULL on error. + * Free the returned object with g_object_unref(). + * + * Since: 2.32 + **/ +GCredentials * +g_unix_connection_receive_credentials_finish (GUnixConnection *connection, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, connection), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +}