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