Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright © 2009 Codethink Limited
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * See the included COPYING file for more information.
13 : : *
14 : : * Authors: Ryan Lortie <desrt@desrt.ca>
15 : : */
16 : :
17 : : /**
18 : : * GSocketControlMessage:
19 : : *
20 : : * A `GSocketControlMessage` is a special-purpose utility message that
21 : : * can be sent to or received from a [class@Gio.Socket]. These types of
22 : : * messages are often called ‘ancillary data’.
23 : : *
24 : : * The message can represent some sort of special instruction to or
25 : : * information from the socket or can represent a special kind of
26 : : * transfer to the peer (for example, sending a file descriptor over
27 : : * a UNIX socket).
28 : : *
29 : : * These messages are sent with [method@Gio.Socket.send_message] and received
30 : : * with [method@Gio.Socket.receive_message].
31 : : *
32 : : * To extend the set of control messages that can be sent, subclass this
33 : : * class and override the `get_size`, `get_level`, `get_type` and `serialize`
34 : : * methods.
35 : : *
36 : : * To extend the set of control messages that can be received, subclass
37 : : * this class and implement the `deserialize` method. Also, make sure your
38 : : * class is registered with the [type@GObject.Type] type system before calling
39 : : * [method@Gio.Socket.receive_message] to read such a message.
40 : : *
41 : : * Since: 2.22
42 : : */
43 : :
44 : : #include "config.h"
45 : : #include "gsocketcontrolmessage.h"
46 : : #include "gnetworkingprivate.h"
47 : : #include "glibintl.h"
48 : :
49 : : #ifndef G_OS_WIN32
50 : : #include "gunixcredentialsmessage.h"
51 : : #include "gunixfdmessage.h"
52 : : #endif
53 : : #include "giptosmessage.h"
54 : : #include "gipv6tclassmessage.h"
55 : :
56 : 12736 : G_DEFINE_ABSTRACT_TYPE (GSocketControlMessage, g_socket_control_message, G_TYPE_OBJECT)
57 : :
58 : : /**
59 : : * g_socket_control_message_get_size:
60 : : * @message: a #GSocketControlMessage
61 : : *
62 : : * Returns the space required for the control message, not including
63 : : * headers or alignment.
64 : : *
65 : : * Returns: The number of bytes required.
66 : : *
67 : : * Since: 2.22
68 : : */
69 : : gsize
70 : 4882 : g_socket_control_message_get_size (GSocketControlMessage *message)
71 : : {
72 : 4882 : g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
73 : :
74 : 4882 : return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_size (message);
75 : : }
76 : :
77 : : /**
78 : : * g_socket_control_message_get_level:
79 : : * @message: a #GSocketControlMessage
80 : : *
81 : : * Returns the "level" (i.e. the originating protocol) of the control message.
82 : : * This is often SOL_SOCKET.
83 : : *
84 : : * Returns: an integer describing the level
85 : : *
86 : : * Since: 2.22
87 : : */
88 : : int
89 : 2441 : g_socket_control_message_get_level (GSocketControlMessage *message)
90 : : {
91 : 2441 : g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
92 : :
93 : 2441 : return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_level (message);
94 : : }
95 : :
96 : : /**
97 : : * g_socket_control_message_get_msg_type:
98 : : * @message: a #GSocketControlMessage
99 : : *
100 : : * Returns the protocol specific type of the control message.
101 : : * For instance, for UNIX fd passing this would be SCM_RIGHTS.
102 : : *
103 : : * Returns: an integer describing the type of control message
104 : : *
105 : : * Since: 2.22
106 : : */
107 : : int
108 : 2441 : g_socket_control_message_get_msg_type (GSocketControlMessage *message)
109 : : {
110 : 2441 : g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
111 : :
112 : 2441 : return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_type (message);
113 : : }
114 : :
115 : : /**
116 : : * g_socket_control_message_serialize:
117 : : * @message: a #GSocketControlMessage
118 : : * @data: (not nullable): A buffer to write data to
119 : : *
120 : : * Converts the data in the message to bytes placed in the
121 : : * message.
122 : : *
123 : : * @data is guaranteed to have enough space to fit the size
124 : : * returned by g_socket_control_message_get_size() on this
125 : : * object.
126 : : *
127 : : * Since: 2.22
128 : : */
129 : : void
130 : 2441 : g_socket_control_message_serialize (GSocketControlMessage *message,
131 : : gpointer data)
132 : : {
133 : 2441 : g_return_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message));
134 : :
135 : 2441 : G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->serialize (message, data);
136 : : }
137 : :
138 : :
139 : : static void
140 : 2472 : g_socket_control_message_init (GSocketControlMessage *message)
141 : : {
142 : 2472 : }
143 : :
144 : : static void
145 : 104 : g_socket_control_message_class_init (GSocketControlMessageClass *class)
146 : : {
147 : 104 : }
148 : :
149 : : static GSocketControlMessage *
150 : 58 : try_deserialize_message_type (GType msgtype, int level, int type, gsize size, gpointer data)
151 : : {
152 : : GSocketControlMessage *message;
153 : :
154 : 58 : GSocketControlMessageClass *class = g_type_class_ref (msgtype);
155 : 58 : message = class->deserialize (level, type, size, data);
156 : 58 : g_type_class_unref (class);
157 : :
158 : 58 : return message;
159 : : }
160 : :
161 : : /**
162 : : * g_socket_control_message_deserialize:
163 : : * @level: a socket level
164 : : * @type: a socket control message type for the given @level
165 : : * @size: the size of the data in bytes
166 : : * @data: (array length=size) (element-type guint8): pointer to the message data
167 : : *
168 : : * Tries to deserialize a socket control message of a given
169 : : * @level and @type. This will ask all known (to GType) subclasses
170 : : * of #GSocketControlMessage if they can understand this kind
171 : : * of message and if so deserialize it into a #GSocketControlMessage.
172 : : *
173 : : * If there is no implementation for this kind of control message, %NULL
174 : : * will be returned.
175 : : *
176 : : * Returns: (nullable) (transfer full): the deserialized message or %NULL
177 : : *
178 : : * Since: 2.22
179 : : */
180 : : GSocketControlMessage *
181 : 28 : g_socket_control_message_deserialize (int level,
182 : : int type,
183 : : gsize size,
184 : : gpointer data)
185 : : {
186 : : GSocketControlMessage *message;
187 : : GType *message_types;
188 : : guint n_message_types;
189 : : guint i;
190 : :
191 : : static gsize builtin_messages_initialized = FALSE;
192 : : static GType builtin_messages[5];
193 : : static guint n_builtin_messages = 0;
194 : :
195 : 28 : if (g_once_init_enter (&builtin_messages_initialized))
196 : : {
197 : 12 : i = 0;
198 : :
199 : : #ifndef G_OS_WIN32
200 : 12 : builtin_messages[i++] = G_TYPE_UNIX_CREDENTIALS_MESSAGE;
201 : 12 : builtin_messages[i++] = G_TYPE_UNIX_FD_MESSAGE;
202 : : #endif
203 : 12 : builtin_messages[i++] = G_TYPE_IP_TOS_MESSAGE;
204 : 12 : builtin_messages[i++] = G_TYPE_IPV6_TCLASS_MESSAGE;
205 : :
206 : 12 : n_builtin_messages = i;
207 : :
208 : : /* Ensure we know about the built in types */
209 : 60 : for (i = 0; builtin_messages[i]; ++i)
210 : : {
211 : 48 : g_type_ensure (builtin_messages[i]);
212 : : }
213 : :
214 : 12 : g_once_init_leave (&builtin_messages_initialized, TRUE);
215 : : }
216 : :
217 : 28 : message_types = g_type_children (G_TYPE_SOCKET_CONTROL_MESSAGE, &n_message_types);
218 : :
219 : 28 : message = NULL;
220 : :
221 : : /* First try to deserialize using message types registered by application. */
222 : 28 : if (n_message_types > n_builtin_messages)
223 : : {
224 : 2 : for (i = 0; i < n_message_types; i++)
225 : : {
226 : : guint j;
227 : 2 : gboolean is_builtin = FALSE;
228 : :
229 : 7 : for (j = 0; builtin_messages[j]; ++j)
230 : : {
231 : 6 : if (message_types[i] == builtin_messages[j])
232 : : {
233 : 1 : is_builtin = TRUE;
234 : 1 : break;
235 : : }
236 : : }
237 : :
238 : 2 : if (!is_builtin)
239 : : {
240 : 1 : message = try_deserialize_message_type (message_types[i], level,
241 : : type, size, data);
242 : :
243 : 1 : if (message != NULL)
244 : 1 : break;
245 : : }
246 : : }
247 : : }
248 : :
249 : 28 : g_free (message_types);
250 : :
251 : : /* Fallback to builtin message types. */
252 : 28 : if (message == NULL)
253 : : {
254 : 57 : for (i = 0; builtin_messages[i]; i++)
255 : : {
256 : 57 : message = try_deserialize_message_type (builtin_messages[i], level,
257 : : type, size, data);
258 : :
259 : 57 : if (message != NULL)
260 : 27 : break;
261 : : }
262 : : }
263 : :
264 : : /* It's not a bug if we can't deserialize the control message - for
265 : : * example, the control message may be be discarded if it is deemed
266 : : * empty, see e.g.
267 : : *
268 : : * https://gitlab.gnome.org/GNOME/glib/commit/ec91ed00f14c70cca9749347b8ebc19d72d9885b
269 : : *
270 : : * Therefore, it's not appropriate to print a warning about not
271 : : * being able to deserialize the message.
272 : : */
273 : :
274 : 28 : return message;
275 : : }
|