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