Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/ginetsocketaddress.c
Line
Count
Source (jump to first uncovered line)
1
/* GIO - GLib Input, Output and Streaming Library
2
 *
3
 * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General
16
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17
 *
18
 * Authors: Christian Kellner <gicmo@gnome.org>
19
 *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
20
 */
21
22
#include <config.h>
23
#include <glib.h>
24
#include <string.h>
25
26
#include "ginetsocketaddress.h"
27
#include "ginetaddress.h"
28
#include "gnetworkingprivate.h"
29
#include "gsocketconnectable.h"
30
#include "gioerror.h"
31
#include "glibintl.h"
32
33
34
/**
35
 * SECTION:ginetsocketaddress
36
 * @short_description: Internet GSocketAddress
37
 * @include: gio/gio.h
38
 *
39
 * An IPv4 or IPv6 socket address; that is, the combination of a
40
 * #GInetAddress and a port number.
41
 */
42
43
/**
44
 * GInetSocketAddress:
45
 *
46
 * An IPv4 or IPv6 socket address, corresponding to a struct
47
 * sockaddr_in or struct sockaddr_in6.
48
 */
49
50
struct _GInetSocketAddressPrivate
51
{
52
  GInetAddress *address;
53
  guint16       port;
54
  guint32       flowinfo;
55
  guint32       scope_id;
56
};
57
58
static void   g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface);
59
static gchar *g_inet_socket_address_connectable_to_string  (GSocketConnectable      *connectable);
60
61
G_DEFINE_TYPE_WITH_CODE (GInetSocketAddress, g_inet_socket_address, G_TYPE_SOCKET_ADDRESS,
62
                         G_ADD_PRIVATE (GInetSocketAddress)
63
                         G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
64
                                                g_inet_socket_address_connectable_iface_init))
65
66
enum {
67
  PROP_0,
68
  PROP_ADDRESS,
69
  PROP_PORT,
70
  PROP_FLOWINFO,
71
  PROP_SCOPE_ID
72
};
73
74
static void
75
g_inet_socket_address_dispose (GObject *object)
76
0
{
77
0
  GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
78
79
0
  g_clear_object (&(address->priv->address));
80
81
0
  G_OBJECT_CLASS (g_inet_socket_address_parent_class)->dispose (object);
82
0
}
83
84
static void
85
g_inet_socket_address_get_property (GObject    *object,
86
                                    guint       prop_id,
87
                                    GValue     *value,
88
                                    GParamSpec *pspec)
89
0
{
90
0
  GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
91
92
0
  switch (prop_id)
93
0
    {
94
0
      case PROP_ADDRESS:
95
0
        g_value_set_object (value, address->priv->address);
96
0
        break;
97
98
0
      case PROP_PORT:
99
0
        g_value_set_uint (value, address->priv->port);
100
0
        break;
101
102
0
      case PROP_FLOWINFO:
103
0
  g_return_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6);
104
0
        g_value_set_uint (value, address->priv->flowinfo);
105
0
        break;
106
107
0
      case PROP_SCOPE_ID:
108
0
  g_return_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6);
109
0
        g_value_set_uint (value, address->priv->scope_id);
110
0
        break;
111
112
0
      default:
113
0
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
114
0
    }
115
0
}
116
117
static void
118
g_inet_socket_address_set_property (GObject      *object,
119
                                    guint         prop_id,
120
                                    const GValue *value,
121
                                    GParamSpec   *pspec)
122
0
{
123
0
  GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
124
125
0
  switch (prop_id)
126
0
    {
127
0
      case PROP_ADDRESS:
128
0
        address->priv->address = g_object_ref (g_value_get_object (value));
129
0
        break;
130
131
0
      case PROP_PORT:
132
0
        address->priv->port = (guint16) g_value_get_uint (value);
133
0
        break;
134
135
0
      case PROP_FLOWINFO:
136
  /* We can't test that address->priv->address is IPv6 here,
137
   * since this property might get set before PROP_ADDRESS.
138
   */
139
0
        address->priv->flowinfo = g_value_get_uint (value);
140
0
        break;
141
142
0
      case PROP_SCOPE_ID:
143
0
        address->priv->scope_id = g_value_get_uint (value);
144
0
        break;
145
146
0
      default:
147
0
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
148
0
    }
149
0
}
150
151
static GSocketFamily
152
g_inet_socket_address_get_family (GSocketAddress *address)
153
0
{
154
0
  GInetSocketAddress *addr;
155
156
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
157
158
0
  addr = G_INET_SOCKET_ADDRESS (address);
159
160
0
  return g_inet_address_get_family (addr->priv->address);
161
0
}
162
163
static gssize
164
g_inet_socket_address_get_native_size (GSocketAddress *address)
165
0
{
166
0
  GInetSocketAddress *addr;
167
0
  GSocketFamily family;
168
169
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
170
171
0
  addr = G_INET_SOCKET_ADDRESS (address);
172
0
  family = g_inet_address_get_family (addr->priv->address);
173
174
0
  if (family == AF_INET)
175
0
    return sizeof (struct sockaddr_in);
176
0
  else if (family == AF_INET6)
177
0
    return sizeof (struct sockaddr_in6);
178
0
  else
179
0
    return -1;
180
0
}
181
182
static gboolean
183
g_inet_socket_address_to_native (GSocketAddress  *address,
184
                                 gpointer         dest,
185
         gsize            destlen,
186
         GError         **error)
187
0
{
188
0
  GInetSocketAddress *addr;
189
0
  GSocketFamily family;
190
191
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), FALSE);
192
193
0
  addr = G_INET_SOCKET_ADDRESS (address);
194
0
  family = g_inet_address_get_family (addr->priv->address);
195
196
0
  if (family == AF_INET)
197
0
    {
198
0
      struct sockaddr_in *sock = (struct sockaddr_in *) dest;
199
200
0
      if (destlen < sizeof (*sock))
201
0
  {
202
0
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
203
0
             _("Not enough space for socket address"));
204
0
    return FALSE;
205
0
  }
206
207
0
      sock->sin_family = AF_INET;
208
0
      sock->sin_port = g_htons (addr->priv->port);
209
0
      memcpy (&(sock->sin_addr.s_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin_addr));
210
0
      memset (sock->sin_zero, 0, sizeof (sock->sin_zero));
211
0
      return TRUE;
212
0
    }
213
0
  else if (family == AF_INET6)
214
0
    {
215
0
      struct sockaddr_in6 *sock = (struct sockaddr_in6 *) dest;
216
217
0
      if (destlen < sizeof (*sock))
218
0
  {
219
0
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
220
0
             _("Not enough space for socket address"));
221
0
    return FALSE;
222
0
  }
223
224
0
      memset (sock, 0, sizeof (*sock));
225
0
      sock->sin6_family = AF_INET6;
226
0
      sock->sin6_port = g_htons (addr->priv->port);
227
0
      sock->sin6_flowinfo = addr->priv->flowinfo;
228
0
      sock->sin6_scope_id = addr->priv->scope_id;
229
0
      memcpy (&(sock->sin6_addr.s6_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin6_addr));
230
0
      return TRUE;
231
0
    }
232
0
  else
233
0
    {
234
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
235
0
         _("Unsupported socket address"));
236
0
      return FALSE;
237
0
    }
238
0
}
239
240
static void
241
g_inet_socket_address_class_init (GInetSocketAddressClass *klass)
242
0
{
243
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
244
0
  GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
245
246
0
  gobject_class->dispose = g_inet_socket_address_dispose;
247
0
  gobject_class->set_property = g_inet_socket_address_set_property;
248
0
  gobject_class->get_property = g_inet_socket_address_get_property;
249
250
0
  gsocketaddress_class->get_family = g_inet_socket_address_get_family;
251
0
  gsocketaddress_class->to_native = g_inet_socket_address_to_native;
252
0
  gsocketaddress_class->get_native_size = g_inet_socket_address_get_native_size;
253
254
0
  g_object_class_install_property (gobject_class, PROP_ADDRESS,
255
0
                                   g_param_spec_object ("address",
256
0
                                                        P_("Address"),
257
0
                                                        P_("The address"),
258
0
                                                        G_TYPE_INET_ADDRESS,
259
0
                                                        G_PARAM_CONSTRUCT_ONLY |
260
0
                                                        G_PARAM_READWRITE |
261
0
                                                        G_PARAM_STATIC_STRINGS));
262
263
0
  g_object_class_install_property (gobject_class, PROP_PORT,
264
0
                                   g_param_spec_uint ("port",
265
0
                                                      P_("Port"),
266
0
                                                      P_("The port"),
267
0
                                                      0,
268
0
                                                      65535,
269
0
                                                      0,
270
0
                                                      G_PARAM_CONSTRUCT_ONLY |
271
0
                                                      G_PARAM_READWRITE |
272
0
                                                      G_PARAM_STATIC_STRINGS));
273
274
  /**
275
   * GInetSocketAddress:flowinfo:
276
   *
277
   * The `sin6_flowinfo` field, for IPv6 addresses.
278
   *
279
   * Since: 2.32
280
   */
281
0
  g_object_class_install_property (gobject_class, PROP_FLOWINFO,
282
0
                                   g_param_spec_uint ("flowinfo",
283
0
                                                      P_("Flow info"),
284
0
                                                      P_("IPv6 flow info"),
285
0
                                                      0,
286
0
                                                      G_MAXUINT32,
287
0
                                                      0,
288
0
                                                      G_PARAM_CONSTRUCT_ONLY |
289
0
                                                      G_PARAM_READWRITE |
290
0
                                                      G_PARAM_STATIC_STRINGS));
291
292
  /**
293
   * GInetSocketAddress:scope_id:
294
   *
295
   * The `sin6_scope_id` field, for IPv6 addresses.
296
   *
297
   * Since: 2.32
298
   */
299
0
  g_object_class_install_property (gobject_class, PROP_SCOPE_ID,
300
0
                                   g_param_spec_uint ("scope-id",
301
0
                                                      P_("Scope ID"),
302
0
                                                      P_("IPv6 scope ID"),
303
0
                                                      0,
304
0
                                                      G_MAXUINT32,
305
0
                                                      0,
306
0
                                                      G_PARAM_CONSTRUCT_ONLY |
307
0
                                                      G_PARAM_READWRITE |
308
0
                                                      G_PARAM_STATIC_STRINGS));
309
0
}
310
311
static void
312
g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
313
0
{
314
0
  GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
315
316
0
  iface->enumerate = parent_iface->enumerate;
317
0
  iface->proxy_enumerate = parent_iface->proxy_enumerate;
318
0
  iface->to_string = g_inet_socket_address_connectable_to_string;
319
0
}
320
321
static gchar *
322
g_inet_socket_address_connectable_to_string (GSocketConnectable *connectable)
323
0
{
324
0
  GInetSocketAddress *sa;
325
0
  GInetAddress *a;
326
0
  gchar *a_string;
327
0
  GString *out;
328
0
  guint16 port;
329
330
0
  sa = G_INET_SOCKET_ADDRESS (connectable);
331
0
  a = g_inet_socket_address_get_address (sa);
332
0
  out = g_string_new ("");
333
334
  /* Address. */
335
0
  a_string = g_inet_address_to_string (a);
336
0
  g_string_append (out, a_string);
337
0
  g_free (a_string);
338
339
  /* Scope ID (IPv6 only). */
340
0
  if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6 &&
341
0
      g_inet_socket_address_get_scope_id (sa) != 0)
342
0
    {
343
0
      g_string_append_printf (out, "%%%u",
344
0
                              g_inet_socket_address_get_scope_id (sa));
345
0
    }
346
347
  /* Port. */
348
0
  port = g_inet_socket_address_get_port (sa);
349
0
  if (port != 0)
350
0
    {
351
      /* Disambiguate ports from IPv6 addresses using square brackets. */
352
0
      if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6)
353
0
        {
354
0
          g_string_prepend (out, "[");
355
0
          g_string_append (out, "]");
356
0
        }
357
358
0
      g_string_append_printf (out, ":%u", port);
359
0
    }
360
361
0
  return g_string_free (out, FALSE);
362
0
}
363
364
static void
365
g_inet_socket_address_init (GInetSocketAddress *address)
366
0
{
367
0
  address->priv = g_inet_socket_address_get_instance_private (address);
368
0
}
369
370
/**
371
 * g_inet_socket_address_new:
372
 * @address: a #GInetAddress
373
 * @port: a port number
374
 *
375
 * Creates a new #GInetSocketAddress for @address and @port.
376
 *
377
 * Returns: a new #GInetSocketAddress
378
 *
379
 * Since: 2.22
380
 */
381
GSocketAddress *
382
g_inet_socket_address_new (GInetAddress *address,
383
                           guint16       port)
384
0
{
385
0
  return g_object_new (G_TYPE_INET_SOCKET_ADDRESS,
386
0
           "address", address,
387
0
           "port", port,
388
0
           NULL);
389
0
}
390
391
/**
392
 * g_inet_socket_address_new_from_string:
393
 * @address: the string form of an IP address
394
 * @port: a port number
395
 *
396
 * Creates a new #GInetSocketAddress for @address and @port.
397
 *
398
 * If @address is an IPv6 address, it can also contain a scope ID
399
 * (separated from the address by a `%`).
400
 *
401
 * Returns: (nullable) (transfer full): a new #GInetSocketAddress,
402
 * or %NULL if @address cannot be parsed.
403
 *
404
 * Since: 2.40
405
 */
406
GSocketAddress *
407
g_inet_socket_address_new_from_string (const char *address,
408
                                       guint       port)
409
0
{
410
0
  static struct addrinfo *hints, hints_struct;
411
0
  GSocketAddress *saddr;
412
0
  GInetAddress *iaddr;
413
0
  struct addrinfo *res;
414
0
  gint status;
415
416
0
  if (strchr (address, ':'))
417
0
    {
418
      /* IPv6 address (or it's invalid). We use getaddrinfo() because
419
       * it will handle parsing a scope_id as well.
420
       */
421
422
0
      if (G_UNLIKELY (g_once_init_enter (&hints)))
423
0
        {
424
0
          hints_struct.ai_family = AF_UNSPEC;
425
0
          hints_struct.ai_socktype = SOCK_STREAM;
426
0
          hints_struct.ai_protocol = 0;
427
0
          hints_struct.ai_flags = AI_NUMERICHOST;
428
0
          g_once_init_leave (&hints, &hints_struct);
429
0
        }
430
431
0
      status = getaddrinfo (address, NULL, hints, &res);
432
0
      if (status != 0)
433
0
        return NULL;
434
435
0
      if (res->ai_family == AF_INET6 &&
436
0
          res->ai_addrlen == sizeof (struct sockaddr_in6))
437
0
        {
438
0
          ((struct sockaddr_in6 *)res->ai_addr)->sin6_port = g_htons (port);
439
0
          saddr = g_socket_address_new_from_native (res->ai_addr, res->ai_addrlen);
440
0
        }
441
0
      else
442
0
        saddr = NULL;
443
444
0
      freeaddrinfo (res);
445
0
    }
446
0
  else
447
0
    {
448
      /* IPv4 (or invalid). We don't want to use getaddrinfo() here,
449
       * because it accepts the stupid "IPv4 numbers-and-dots
450
       * notation" addresses that are never used for anything except
451
       * phishing. Since we don't have to worry about scope IDs for
452
       * IPv4, we can just use g_inet_address_new_from_string().
453
       */
454
0
      iaddr = g_inet_address_new_from_string (address);
455
0
      if (!iaddr)
456
0
        return NULL;
457
458
0
      g_warn_if_fail (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4);
459
460
0
      saddr = g_inet_socket_address_new (iaddr, port);
461
0
      g_object_unref (iaddr);
462
0
    }
463
464
0
  return saddr;
465
0
}
466
467
/**
468
 * g_inet_socket_address_get_address:
469
 * @address: a #GInetSocketAddress
470
 *
471
 * Gets @address's #GInetAddress.
472
 *
473
 * Returns: (transfer none): the #GInetAddress for @address, which must be
474
 * g_object_ref()'d if it will be stored
475
 *
476
 * Since: 2.22
477
 */
478
GInetAddress *
479
g_inet_socket_address_get_address (GInetSocketAddress *address)
480
0
{
481
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), NULL);
482
483
0
  return address->priv->address;
484
0
}
485
486
/**
487
 * g_inet_socket_address_get_port:
488
 * @address: a #GInetSocketAddress
489
 *
490
 * Gets @address's port.
491
 *
492
 * Returns: the port for @address
493
 *
494
 * Since: 2.22
495
 */
496
guint16
497
g_inet_socket_address_get_port (GInetSocketAddress *address)
498
0
{
499
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
500
501
0
  return address->priv->port;
502
0
}
503
504
505
/**
506
 * g_inet_socket_address_get_flowinfo:
507
 * @address: a %G_SOCKET_FAMILY_IPV6 #GInetSocketAddress
508
 *
509
 * Gets the `sin6_flowinfo` field from @address,
510
 * which must be an IPv6 address.
511
 *
512
 * Returns: the flowinfo field
513
 *
514
 * Since: 2.32
515
 */
516
guint32
517
g_inet_socket_address_get_flowinfo (GInetSocketAddress *address)
518
0
{
519
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
520
0
  g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0);
521
522
0
  return address->priv->flowinfo;
523
0
}
524
525
/**
526
 * g_inet_socket_address_get_scope_id:
527
 * @address: a %G_SOCKET_FAMILY_IPV6 #GInetAddress
528
 *
529
 * Gets the `sin6_scope_id` field from @address,
530
 * which must be an IPv6 address.
531
 *
532
 * Returns: the scope id field
533
 *
534
 * Since: 2.32
535
 */
536
guint32
537
g_inet_socket_address_get_scope_id (GInetSocketAddress *address)
538
0
{
539
0
  g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
540
0
  g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0);
541
542
0
  return address->priv->scope_id;
543
0
}