glib/gio/gunixconnection.c
Alexander Larsson 5cd86fbda6 Remove protocol names, instead use an enum with common protocols
The whole protocol name thing is pretty weird. The getprotobyname functions
seem to only specify one mapping for name <-> ids, so all families/types
must use the same values. Plus the values used for the protocols are
standardized by IANA, so are always the same.

So, we drop using names for protocols, intead introducing an enum with
a few commonly availible and used protocols.
2009-05-20 12:14:50 +02:00

294 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_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"