/* GIO - GLib Input, Output and Streaming Library * * Copyright © 2009 Codethink Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2 of the licence or (at * your option) any later version. * * See the included COPYING file for more information. * * Authors: Ryan Lortie */ #include "config.h" #include "gunixconnection.h" #include "glibintl.h" /** * SECTION: gunixconnection * @title: GUnixConnection * @short_description: a Unix domain #GSocketConnection * @see_also: #GSocketConnection. * * This is the subclass of #GSocketConnection that is created * for UNIX domain sockets. * * It contains functions to do some of the unix socket specific * functionallity like passing file descriptors. * * Since: 2.22 **/ #include #include #include #include #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, G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, 0); ); /** * 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. * * Passes a file descriptor to the recieving side of the * connection. The recieving 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 * stream, as this is required for fd passing to work on some * implementations. * * Returns: a %TRUE on success, %NULL on error. * * Since: 2.22 **/ gboolean g_unix_connection_send_fd (GUnixConnection *connection, gint fd, GCancellable *cancellable, GError **error) { GSocketControlMessage *scm; GSocket *socket; g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), FALSE); g_return_val_if_fail (fd >= 0, FALSE); scm = g_unix_fd_message_new (); if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (scm), fd, error)) { g_object_unref (scm); return FALSE; } g_object_get (connection, "socket", &socket, NULL); if (!g_socket_condition_wait (socket, G_IO_OUT, cancellable, error) || g_socket_send_message (socket, NULL, NULL, 0, &scm, 1, 0, error) != 1) /* XXX could it 'fail' with zero? */ { g_object_unref (socket); g_object_unref (scm); return FALSE; } g_object_unref (socket); g_object_unref (scm); return TRUE; } /** * g_unix_connection_receive_fd: * @connection: a #GUnixConnection. * @cancellable: optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting, or %NULL to ignore. * * Recieves a file descriptor from the sending end of the * connection. The sending end has to call g_unix_connection_send_fd() * for this to work. * * As well as reading the fd this also reads a single byte from the * stream, as this is required for fd passing to work on some * implementations. * * Returns: a file descriptor on success, -1 on error. * * Since: 2.22 **/ gint g_unix_connection_receive_fd (GUnixConnection *connection, GCancellable *cancellable, GError **error) { GSocketControlMessage **scms; gint *fds, nfd, fd, nscm; GUnixFDMessage *fdmsg; GSocket *socket; g_return_val_if_fail (G_IS_UNIX_CONNECTION (connection), -1); g_object_get (connection, "socket", &socket, NULL); if (!g_socket_condition_wait (socket, G_IO_IN, cancellable, error) || g_socket_receive_message (socket, NULL, NULL, 0, &scms, &nscm, NULL, error) != 1) /* XXX it _could_ 'fail' with zero. */ { g_object_unref (socket); return -1; } g_object_unref (socket); if (nscm != 1) { gint i; g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Expecting 1 control message, got %d"), nscm); for (i = 0; i < nscm; i++) g_object_unref (scms[i]); g_free (scms); return -1; } if (!G_IS_UNIX_FD_MESSAGE (scms[0])) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unexpected type of ancillary data")); g_object_unref (scms[0]); g_free (scms); return -1; } fdmsg = G_UNIX_FD_MESSAGE (scms[0]); g_free (scms); fds = g_unix_fd_message_steal_fds (fdmsg, &nfd); g_object_unref (fdmsg); if (nfd != 1) { gint i; g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Expecting one fd, but got %d\n"), nfd); for (i = 0; i < nfd; i++) close (fds[i]); g_free (fds); return -1; } fd = *fds; g_free (fds); if (fd < 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Received invalid fd")); fd = -1; } return fd; } static void g_unix_connection_init (GUnixConnection *connection) { } static void g_unix_connection_class_init (GUnixConnectionClass *class) { } /* TODO: Other stuff we might want to add are: void g_unix_connection_send_fd_async (GUnixConnection *connection, gint fd, gboolean close, gint io_priority, GAsyncReadyCallback callback, gpointer user_data); gboolean g_unix_connection_send_fd_finish (GUnixConnection *connection, GError **error); gboolean g_unix_connection_send_fds (GUnixConnection *connection, gint *fds, gint nfds, GError **error); void g_unix_connection_send_fds_async (GUnixConnection *connection, gint *fds, gint nfds, gint io_priority, GAsyncReadyCallback callback, gpointer user_data); gboolean g_unix_connection_send_fds_finish (GUnixConnection *connection, GError **error); void g_unix_connection_receive_fd_async (GUnixConnection *connection, gint io_priority, GAsyncReadyCallback callback, gpointer user_data); gint g_unix_connection_receive_fd_finish (GUnixConnection *connection, 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, guint64 gid, GError **error); void g_unix_connection_send_fake_credentials_async (GUnixConnection *connection, guint64 pid, guint64 uid, guint64 gid, gint io_priority, GAsyncReadyCallback callback, gpointer user_data); 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); */ #define __G_UNIX_CONNECTION_C__ #include "gioaliasdef.c"