Add gnetworking.h
[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 GUnixFDList
19  * @include: gio/gunixfdmessage.h
20  * @see_also: #GUnixConnection, #GUnixFDList, #GSocketControlMessage
21  *
22  * This #GSocketControlMessage contains a #GUnixFDList.
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). The file descriptors are copied
26  * between processes by the kernel.
27  *
28  * For an easier way to send and receive file descriptors over
29  * stream-oriented UNIX sockets, see g_unix_connection_send_fd() and
30  * g_unix_connection_receive_fd().
31  *
32  * Note that <filename>&lt;gio/gunixfdmessage.h&gt;</filename> belongs to
33  * the UNIX-specific GIO interfaces, thus you have to use the
34  * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
35  **/
36
37 #include "config.h"
38
39 #include <unistd.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <errno.h>
43
44 #include "gunixfdmessage.h"
45 #include "gunixfdlist.h"
46 #include "gnetworking.h"
47 #include "gioerror.h"
48
49
50
51 G_DEFINE_TYPE (GUnixFDMessage, g_unix_fd_message,
52                G_TYPE_SOCKET_CONTROL_MESSAGE);
53
54 struct _GUnixFDMessagePrivate
55 {
56   GUnixFDList *list;
57 };
58
59 static gsize
60 g_unix_fd_message_get_size (GSocketControlMessage *message)
61 {
62   GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
63
64   return g_unix_fd_list_get_length (fd_message->priv->list) * sizeof (gint);
65 }
66
67 static int
68 g_unix_fd_message_get_level (GSocketControlMessage *message)
69 {
70   return SOL_SOCKET;
71 }
72
73 static int
74 g_unix_fd_message_get_msg_type (GSocketControlMessage *message)
75 {
76   return SCM_RIGHTS;
77 }
78
79 static GSocketControlMessage *
80 g_unix_fd_message_deserialize (int      level,
81                                int      type,
82                                gsize    size,
83                                gpointer data)
84 {
85   GSocketControlMessage *message;
86   GUnixFDList *list;
87   gint n, s, i;
88   gint *fds;
89
90   if (level != SOL_SOCKET ||
91       type != SCM_RIGHTS)
92     return NULL;
93   
94   if (size % 4 > 0)
95     {
96       g_warning ("Kernel returned non-integral number of fds");
97       return NULL;
98     }
99
100   fds = data;
101   n = size / sizeof (gint);
102
103   /* Note we probably handled this in gsocket.c already if we're on
104    * Linux and have MSG_CMSG_CLOEXEC, but this code remains as a fallback
105    * in case the kernel is too old for MSG_CMSG_CLOEXEC.
106    */
107   for (i = 0; i < n; i++)
108     {
109       do
110         s = fcntl (fds[i], F_SETFD, FD_CLOEXEC);
111       while (s < 0 && errno == EINTR);
112
113       if (s < 0)
114         {
115           g_warning ("Error setting close-on-exec flag on incoming fd: %s",
116                      g_strerror (errno));
117           return NULL;
118         }
119     }
120
121   list = g_unix_fd_list_new_from_array (fds, n);
122   message = g_unix_fd_message_new_with_fd_list (list);
123   g_object_unref (list);
124
125   return message;
126 }
127
128 static void
129 g_unix_fd_message_serialize (GSocketControlMessage *message,
130                              gpointer               data)
131 {
132   GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
133   const gint *fds;
134   gint n_fds;
135
136   fds = g_unix_fd_list_peek_fds (fd_message->priv->list, &n_fds);
137   memcpy (data, fds, sizeof (gint) * n_fds);
138 }
139
140 static void
141 g_unix_fd_message_set_property (GObject *object, guint prop_id,
142                                 const GValue *value, GParamSpec *pspec)
143 {
144   GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
145
146   g_assert (message->priv->list == NULL);
147   g_assert_cmpint (prop_id, ==, 1);
148
149   message->priv->list = g_value_dup_object (value);
150
151   if (message->priv->list == NULL)
152     message->priv->list = g_unix_fd_list_new ();
153 }
154
155 /**
156  * g_unix_fd_message_get_fd_list:
157  * @message: a #GUnixFDMessage
158  *
159  * Gets the #GUnixFDList contained in @message.  This function does not
160  * return a reference to the caller, but the returned list is valid for
161  * the lifetime of @message.
162  *
163  * Returns: (transfer none): the #GUnixFDList from @message
164  *
165  * Since: 2.24
166  **/
167 GUnixFDList *
168 g_unix_fd_message_get_fd_list (GUnixFDMessage *message)
169 {
170   return message->priv->list;
171 }
172
173 static void
174 g_unix_fd_message_get_property (GObject *object, guint prop_id,
175                                 GValue *value, GParamSpec *pspec)
176 {
177   GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
178
179   g_assert_cmpint (prop_id, ==, 1);
180
181   g_value_set_object (value, g_unix_fd_message_get_fd_list (message));
182 }
183
184 static void
185 g_unix_fd_message_init (GUnixFDMessage *message)
186 {
187   message->priv = G_TYPE_INSTANCE_GET_PRIVATE (message,
188                                                G_TYPE_UNIX_FD_MESSAGE,
189                                                GUnixFDMessagePrivate);
190 }
191
192 static void
193 g_unix_fd_message_finalize (GObject *object)
194 {
195   GUnixFDMessage *message = G_UNIX_FD_MESSAGE (object);
196
197   g_object_unref (message->priv->list);
198
199   G_OBJECT_CLASS (g_unix_fd_message_parent_class)
200     ->finalize (object);
201 }
202
203 static void
204 g_unix_fd_message_class_init (GUnixFDMessageClass *class)
205 {
206   GSocketControlMessageClass *scm_class = G_SOCKET_CONTROL_MESSAGE_CLASS (class);
207   GObjectClass *object_class = G_OBJECT_CLASS (class);
208
209   g_type_class_add_private (class, sizeof (GUnixFDMessagePrivate));
210   scm_class->get_size = g_unix_fd_message_get_size;
211   scm_class->get_level = g_unix_fd_message_get_level;
212   scm_class->get_type = g_unix_fd_message_get_msg_type;
213   scm_class->serialize = g_unix_fd_message_serialize;
214   scm_class->deserialize = g_unix_fd_message_deserialize;
215   object_class->finalize = g_unix_fd_message_finalize;
216   object_class->set_property = g_unix_fd_message_set_property;
217   object_class->get_property = g_unix_fd_message_get_property;
218
219   g_object_class_install_property (object_class, 1,
220     g_param_spec_object ("fd-list", "file descriptor list",
221                          "The GUnixFDList object to send with the message",
222                          G_TYPE_UNIX_FD_LIST, G_PARAM_STATIC_STRINGS |
223                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
224 }
225
226 /**
227  * g_unix_fd_message_new:
228  *
229  * Creates a new #GUnixFDMessage containing an empty file descriptor
230  * list.
231  *
232  * Returns: a new #GUnixFDMessage
233  *
234  * Since: 2.22
235  **/
236 GSocketControlMessage *
237 g_unix_fd_message_new (void)
238 {
239   return g_object_new (G_TYPE_UNIX_FD_MESSAGE, NULL);
240 }
241
242 /**
243  * g_unix_fd_message_new_with_fd_list:
244  * @fd_list: a #GUnixFDList
245  *
246  * Creates a new #GUnixFDMessage containing @list.
247  *
248  * Returns: a new #GUnixFDMessage
249  *
250  * Since: 2.24
251  **/
252 GSocketControlMessage *
253 g_unix_fd_message_new_with_fd_list (GUnixFDList *fd_list)
254 {
255   return g_object_new (G_TYPE_UNIX_FD_MESSAGE,
256                        "fd-list", fd_list,
257                        NULL);
258 }
259
260 /**
261  * g_unix_fd_message_steal_fds:
262  * @message: a #GUnixFDMessage
263  * @length: (out) (allow-none): pointer to the length of the returned
264  *     array, or %NULL
265  *
266  * Returns the array of file descriptors that is contained in this
267  * object.
268  *
269  * After this call, the descriptors are no longer contained in
270  * @message. Further calls will return an empty list (unless more
271  * descriptors have been added).
272  *
273  * The return result of this function must be freed with g_free().
274  * The caller is also responsible for closing all of the file
275  * descriptors.
276  *
277  * If @length is non-%NULL then it is set to the number of file
278  * descriptors in the returned array. The returned array is also
279  * terminated with -1.
280  *
281  * This function never returns %NULL. In case there are no file
282  * descriptors contained in @message, an empty array is returned.
283  *
284  * Returns: (array length=length) (transfer full): an array of file
285  *     descriptors
286  *
287  * Since: 2.22
288  **/
289 gint *
290 g_unix_fd_message_steal_fds (GUnixFDMessage *message,
291                              gint           *length)
292 {
293   g_return_val_if_fail (G_UNIX_FD_MESSAGE (message), NULL);
294
295   return g_unix_fd_list_steal_fds (message->priv->list, length);
296 }
297
298 /**
299  * g_unix_fd_message_append_fd:
300  * @message: a #GUnixFDMessage
301  * @fd: a valid open file descriptor
302  * @error: a #GError pointer
303  *
304  * Adds a file descriptor to @message.
305  *
306  * The file descriptor is duplicated using dup(). You keep your copy
307  * of the descriptor and the copy contained in @message will be closed
308  * when @message is finalized.
309  *
310  * A possible cause of failure is exceeding the per-process or
311  * system-wide file descriptor limit.
312  *
313  * Returns: %TRUE in case of success, else %FALSE (and @error is set)
314  *
315  * Since: 2.22
316  **/
317 gboolean
318 g_unix_fd_message_append_fd (GUnixFDMessage  *message,
319                              gint             fd,
320                              GError         **error)
321 {
322   g_return_val_if_fail (G_UNIX_FD_MESSAGE (message), FALSE);
323
324   return g_unix_fd_list_append (message->priv->list, fd, error) >= 0;
325 }