03c282541f5206de3bfb1a4118e80491739a0e22
[platform/upstream/glib.git] / gio / gunixfdmessage.c
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 /**
16  * SECTION: gunixfdmessage
17  * @title: GUnixFDMessage
18  * @short_description: A GSocketControlMessage containing a list of
19  * file descriptors
20  * @see_also: #GUnixConnection
21  *
22  * This #GSocketControlMessage contains a list of file descriptors.
23  * It may be sent using g_socket_send_message() and received using
24  * g_socket_receive_message() over UNIX sockets (ie: sockets in the
25  * %G_SOCKET_ADDRESS_UNIX family).
26  *
27  * For an easier way to send and receive file descriptors over
28  * stream-oriented UNIX sockets, see g_unix_connection_send_fd() and
29  * g_unix_connection_receive_fd().
30  */
31
32 #include "config.h"
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39
40 #include "gunixfdmessage.h"
41 #include "gioerror.h"
42
43 #include "gioalias.h"
44
45
46 G_DEFINE_TYPE (GUnixFDMessage, g_unix_fd_message,
47                G_TYPE_SOCKET_CONTROL_MESSAGE);
48
49 struct _GUnixFDMessagePrivate
50 {
51   gint *fds;
52   gint nfd;
53 };
54
55 static gsize
56 g_unix_fd_message_get_size (GSocketControlMessage *message)
57 {
58   GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
59
60   return fd_message->priv->nfd * sizeof (gint);
61 }
62
63 static int
64 g_unix_fd_message_get_level (GSocketControlMessage *message)
65 {
66   return SOL_SOCKET;
67 }
68
69 static int
70 g_unix_fd_message_get_msg_type (GSocketControlMessage *message)
71 {
72   return SCM_RIGHTS;
73 }
74
75 static GSocketControlMessage *
76 g_unix_fd_message_deserialize (int      level,
77                                int      type,
78                                gsize    size,
79                                gpointer data)
80 {
81   GUnixFDMessage *message;
82
83   if (level != SOL_SOCKET ||
84       level != SCM_RIGHTS)
85     return NULL;
86   
87   if (size % 4 > 0)
88     {
89       g_warning ("Kernel returned non-integral number of fds");
90       return NULL;
91     }
92
93   message = g_object_new (G_TYPE_UNIX_FD_MESSAGE, NULL);
94   message->priv->nfd = size / sizeof (gint);
95   message->priv->fds = g_new (gint, message->priv->nfd + 1);
96   memcpy (message->priv->fds, data, size);
97   message->priv->fds[message->priv->nfd] = -1;
98
99   return G_SOCKET_CONTROL_MESSAGE (message);
100 }
101
102 static void
103 g_unix_fd_message_serialize (GSocketControlMessage *message,
104                              gpointer               data)
105 {
106   GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
107   memcpy (data, fd_message->priv->fds,
108           sizeof (gint) * fd_message->priv->nfd);
109 }
110 static void
111 g_unix_fd_message_init (GUnixFDMessage *message)
112 {
113   message->priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
114                                                G_TYPE_UNIX_FD_MESSAGE,
115                                                GUnixFDMessagePrivate);
116 }
117
118 static void
119 g_unix_fd_message_finalize (GObject *object)
120 {
121   GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
122   gint i;
123
124   for (i = 0; i < message->priv->nfd; i++)
125     close (message->priv->fds[i]);
126   g_free (message->priv->fds);
127
128   G_OBJECT_CLASS (g_unix_fd_message_parent_class)
129     ->finalize (object);
130 }
131
132 static void
133 g_unix_fd_message_class_init (GUnixFDMessageClass *class)
134 {
135   GSocketControlMessageClass *scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
136   GObjectClass *object_class = G_OBJECT_CLASS (class);
137
138   g_type_class_add_private (class, sizeof (GUnixFDMessagePrivate));
139   scm_class->get_size = g_unix_fd_message_get_size;
140   scm_class->get_level = g_unix_fd_message_get_level;
141   scm_class->get_type = g_unix_fd_message_get_msg_type;
142   scm_class->serialize = g_unix_fd_message_serialize;
143   scm_class->deserialize = g_unix_fd_message_deserialize;
144   object_class->finalize = g_unix_fd_message_finalize;
145 }
146
147 /**
148  * g_unix_fd_message_new:
149  *
150  * Creates a new #GUnixFDMessage containing no file descriptors.
151  *
152  * Returns: a new #GUnixFDMessage
153  *
154  * Since: 2.22
155  */
156 GSocketControlMessage *
157 g_unix_fd_message_new (void)
158 {
159   return g_object_new (G_TYPE_UNIX_FD_MESSAGE, NULL);
160 }
161
162 /**
163  * g_unix_fd_message_steal_fds:
164  * @message: a #GUnixFDMessage
165  * @length: pointer to the length of the returned array, or %NULL
166  *
167  * Returns the array of file descriptors that is contained in this
168  * object.
169  *
170  * After this call, the descriptors are no longer contained in
171  * @message. Further calls will return an empty list (unless more
172  * descriptors have been added).
173  *
174  * The return result of this function must be freed with g_free().
175  * The caller is also responsible for closing all of the file
176  * descriptors.
177  *
178  * If @length is non-%NULL then it is set to the number of file
179  * descriptors in the returned array. The returned array is also
180  * terminated with -1.
181  *
182  * This function never returns %NULL. In case there are no file
183  * descriptors contained in @message, an empty array is returned.
184  *
185  * Returns: an array of file descriptors
186  *
187  * Since: 2.22
188  */
189 gint *
190 g_unix_fd_message_steal_fds (GUnixFDMessage *message,
191                              gint           *length)
192 {
193   gint *result;
194
195   g_return_val_if_fail (G_IS_UNIX_FD_MESSAGE (message), NULL);
196
197   /* will be true for fresh object or if we were just called */
198   if (message->priv->fds == NULL)
199     {
200       message->priv->fds = g_new (gint, 1);
201       message->priv->fds[0] = -1;
202       message->priv->nfd = 0;
203     }
204
205   if (length)
206     *length = message->priv->nfd;
207   result = message->priv->fds;
208
209   message->priv->fds = NULL;
210   message->priv->nfd = 0;
211
212   return result;
213 }
214
215 /**
216  * g_unix_fd_message_append_fd:
217  * @message: a #GUnixFDMessage
218  * @fd: a valid open file descriptor
219  * @error: a #GError pointer
220  *
221  * Adds a file descriptor to @message.
222  *
223  * The file descriptor is duplicated using dup(). You keep your copy
224  * of the descriptor and the copy contained in @message will be closed
225  * when @message is finalized.
226  *
227  * A possible cause of failure is exceeding the per-process or
228  * system-wide file descriptor limit.
229  *
230  * Returns: %TRUE in case of success, else %FALSE (and @error is set)
231  *
232  * Since: 2.22
233  */
234 gboolean
235 g_unix_fd_message_append_fd (GUnixFDMessage  *message,
236                              gint             fd,
237                              GError         **error)
238 {
239   gint new_fd;
240
241   g_return_val_if_fail (G_IS_UNIX_FD_MESSAGE (message), FALSE);
242   g_return_val_if_fail (fd >= 0, FALSE);
243
244   do
245     new_fd = dup (fd);
246   while (new_fd < 0 && (errno == EINTR));
247
248   if (fd < 0)
249     {
250       int saved_errno = errno;
251
252       g_set_error (error, G_IO_ERROR,
253                    g_io_error_from_errno (saved_errno),
254                    "dup: %s", g_strerror (saved_errno));
255
256       return FALSE;
257     }
258
259   message->priv->fds = g_realloc (message->priv->fds,
260                                   sizeof (gint) *
261                                    (message->priv->nfd + 2));
262   message->priv->fds[message->priv->nfd++] = new_fd;
263   message->priv->fds[message->priv->nfd] = -1;
264
265   return TRUE;
266 }
267
268 #define __G_UNIX_FD_MESSAGE_C__
269 #include "gioaliasdef.c"