mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
53beca955e
Currently, to implement cancellability correctly, all synchronous calls to GSocket must be preceded by a g_socket_condition_wait() call, (even though GSocket does this internally as well) and all asynchronous calls must do occasional manual g_cancellable_is_cancelled() checks. Since it's trivial to do these checks inside GSocket instead, and we don't particularly want to encourage people to use the APIs non-cancellably, move the cancellation support into GSocket and simplify the existing callers. http://bugzilla.gnome.org/show_bug.cgi?id=586797
292 lines
12 KiB
C
292 lines
12 KiB
C
/* 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 <desrt@desrt.ca>
|
|
*/
|
|
|
|
#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 <gio/gsocketcontrolmessage.h>
|
|
#include <gio/gunixfdmessage.h>
|
|
#include <gio/gsocket.h>
|
|
#include <unistd.h>
|
|
|
|
#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,
|
|
G_SOCKET_PROTOCOL_DEFAULT);
|
|
);
|
|
|
|
/**
|
|
* 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_send_message (socket, NULL, NULL, 0, &scm, 1, 0, cancellable, 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
|
|
*
|
|
* Receives 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_receive_message (socket, NULL, NULL, 0,
|
|
&scms, &nscm, NULL, cancellable, 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_literal (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"
|