Coverage Report

Created: 2026-05-23 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/gio/gsocketcontrolmessage.c
Line
Count
Source
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
0
G_DEFINE_ABSTRACT_TYPE (GSocketControlMessage, g_socket_control_message, G_TYPE_OBJECT)
57
0
58
0
/**
59
0
 * g_socket_control_message_get_size:
60
0
 * @message: a #GSocketControlMessage
61
0
 *
62
0
 * Returns the space required for the control message, not including
63
0
 * headers or alignment.
64
0
 *
65
0
 * Returns: The number of bytes required.
66
0
 *
67
0
 * Since: 2.22
68
0
 */
69
0
gsize
70
0
g_socket_control_message_get_size (GSocketControlMessage *message)
71
0
{
72
0
  g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
73
74
0
  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_size (message);
75
0
}
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
g_socket_control_message_get_level (GSocketControlMessage *message)
90
0
{
91
0
  g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
92
93
0
  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_level (message);
94
0
}
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
g_socket_control_message_get_msg_type (GSocketControlMessage *message)
109
0
{
110
0
  g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
111
112
0
  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_type (message);
113
0
}
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
g_socket_control_message_serialize (GSocketControlMessage *message,
131
            gpointer               data)
132
0
{
133
0
  g_return_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message));
134
135
0
  G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->serialize (message, data);
136
0
}
137
138
139
static void
140
g_socket_control_message_init (GSocketControlMessage *message)
141
0
{
142
0
}
143
144
static void
145
g_socket_control_message_class_init (GSocketControlMessageClass *class)
146
0
{
147
0
}
148
149
static GSocketControlMessage *
150
try_deserialize_message_type (GType msgtype, int level, int type, gsize size, gpointer data)
151
0
{
152
0
  GSocketControlMessage *message;
153
154
0
  GSocketControlMessageClass *class = g_type_class_ref (msgtype);
155
0
  message = class->deserialize (level, type, size, data);
156
0
  g_type_class_unref (class);
157
158
0
  return message;
159
0
}
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
g_socket_control_message_deserialize (int      level,
182
              int      type,
183
              gsize    size,
184
              gpointer data)
185
0
{
186
0
  GSocketControlMessage *message;
187
0
  GType *message_types;
188
0
  guint n_message_types;
189
0
  guint i;
190
191
0
  static gsize builtin_messages_initialized = FALSE;
192
0
  static GType builtin_messages[5];
193
0
  static guint n_builtin_messages = 0;
194
195
0
  if (g_once_init_enter (&builtin_messages_initialized))
196
0
    {
197
0
      i = 0;
198
199
0
#ifndef G_OS_WIN32
200
0
      builtin_messages[i++] = G_TYPE_UNIX_CREDENTIALS_MESSAGE;
201
0
      builtin_messages[i++] = G_TYPE_UNIX_FD_MESSAGE;
202
0
#endif
203
0
      builtin_messages[i++] = G_TYPE_IP_TOS_MESSAGE;
204
0
      builtin_messages[i++] = G_TYPE_IPV6_TCLASS_MESSAGE;
205
206
0
      n_builtin_messages = i;
207
208
      /* Ensure we know about the built in types */
209
0
      for (i = 0; builtin_messages[i]; ++i)
210
0
        {
211
0
          g_type_ensure (builtin_messages[i]);
212
0
        }
213
214
0
      g_once_init_leave (&builtin_messages_initialized, TRUE);
215
0
    }
216
217
0
  message_types = g_type_children (G_TYPE_SOCKET_CONTROL_MESSAGE, &n_message_types);
218
219
0
  message = NULL;
220
221
  /* First try to deserialize using message types registered by application. */
222
0
  if (n_message_types > n_builtin_messages)
223
0
    {
224
0
      for (i = 0; i < n_message_types; i++)
225
0
        {
226
0
          guint j;
227
0
          gboolean is_builtin = FALSE;
228
229
0
          for (j = 0; builtin_messages[j]; ++j)
230
0
            {
231
0
              if (message_types[i] == builtin_messages[j])
232
0
                {
233
0
                  is_builtin = TRUE;
234
0
                  break;
235
0
                }
236
0
            }
237
238
0
          if (!is_builtin)
239
0
            {
240
0
              message = try_deserialize_message_type (message_types[i], level,
241
0
                                                      type, size, data);
242
243
0
              if (message != NULL)
244
0
                break;
245
0
            }
246
0
        }
247
0
    }
248
249
0
  g_free (message_types);
250
251
  /* Fallback to builtin message types. */
252
0
  if (message == NULL)
253
0
    {
254
0
      for (i = 0; builtin_messages[i]; i++)
255
0
        {
256
0
          message = try_deserialize_message_type (builtin_messages[i], level,
257
0
                                                  type, size, data);
258
259
0
          if (message != NULL)
260
0
            break;
261
0
        }
262
0
    }
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
0
  return message;
275
0
}