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 : 8585 : 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 : 563 : g_inet_socket_address_dispose (GObject *object)
72 : : {
73 : 563 : GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
74 : :
75 : 563 : g_clear_object (&(address->priv->address));
76 : :
77 : 563 : G_OBJECT_CLASS (g_inet_socket_address_parent_class)->dispose (object);
78 : 563 : }
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, g_inet_socket_address_get_flowinfo (address));
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, g_inet_socket_address_get_scope_id (address));
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 : 2260 : g_inet_socket_address_set_property (GObject *object,
115 : : guint prop_id,
116 : : const GValue *value,
117 : : GParamSpec *pspec)
118 : : {
119 : 2260 : GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
120 : :
121 : 2260 : switch (prop_id)
122 : : {
123 : 565 : case PROP_ADDRESS:
124 : 565 : address->priv->address = g_object_ref (g_value_get_object (value));
125 : 565 : break;
126 : :
127 : 565 : case PROP_PORT:
128 : 565 : address->priv->port = (guint16) g_value_get_uint (value);
129 : 565 : break;
130 : :
131 : 565 : 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 : 565 : address->priv->flowinfo = g_value_get_uint (value);
136 : 565 : break;
137 : :
138 : 565 : case PROP_SCOPE_ID:
139 : 565 : address->priv->scope_id = g_value_get_uint (value);
140 : 565 : break;
141 : :
142 : 0 : default:
143 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144 : : }
145 : 2260 : }
146 : :
147 : : static GSocketFamily
148 : 60 : g_inet_socket_address_get_family (GSocketAddress *address)
149 : : {
150 : : GInetSocketAddress *addr;
151 : :
152 : 60 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
153 : :
154 : 60 : addr = G_INET_SOCKET_ADDRESS (address);
155 : :
156 : 60 : return g_inet_address_get_family (addr->priv->address);
157 : : }
158 : :
159 : : static gssize
160 : 179 : g_inet_socket_address_get_native_size (GSocketAddress *address)
161 : : {
162 : : GInetSocketAddress *addr;
163 : : GSocketFamily family;
164 : :
165 : 179 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
166 : :
167 : 179 : addr = G_INET_SOCKET_ADDRESS (address);
168 : 179 : family = g_inet_address_get_family (addr->priv->address);
169 : :
170 : 179 : if (family == AF_INET)
171 : 120 : return sizeof (struct sockaddr_in);
172 : 59 : else if (family == AF_INET6)
173 : 59 : return sizeof (struct sockaddr_in6);
174 : : else
175 : 0 : return -1;
176 : : }
177 : :
178 : : static gboolean
179 : 182 : 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 : 182 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), FALSE);
188 : :
189 : 182 : addr = G_INET_SOCKET_ADDRESS (address);
190 : 182 : family = g_inet_address_get_family (addr->priv->address);
191 : :
192 : 182 : if (family == AF_INET)
193 : : {
194 : 122 : struct sockaddr_in *sock = (struct sockaddr_in *) dest;
195 : :
196 : 122 : 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 : 122 : sock->sin_family = AF_INET;
204 : 122 : sock->sin_port = g_htons (addr->priv->port);
205 : 122 : memcpy (&(sock->sin_addr.s_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin_addr));
206 : 122 : memset (sock->sin_zero, 0, sizeof (sock->sin_zero));
207 : 122 : return TRUE;
208 : : }
209 : 60 : else if (family == AF_INET6)
210 : : {
211 : 60 : struct sockaddr_in6 *sock = (struct sockaddr_in6 *) dest;
212 : :
213 : 60 : 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 : 60 : memset (sock, 0, sizeof (*sock));
221 : 60 : sock->sin6_family = AF_INET6;
222 : 60 : sock->sin6_port = g_htons (addr->priv->port);
223 : 60 : sock->sin6_flowinfo = g_inet_socket_address_get_flowinfo (addr);
224 : 60 : sock->sin6_scope_id = g_inet_socket_address_get_scope_id (addr);
225 : 60 : memcpy (&(sock->sin6_addr.s6_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin6_addr));
226 : 60 : 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 : 15 : g_inet_socket_address_class_init (GInetSocketAddressClass *klass)
238 : : {
239 : 15 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
240 : 15 : GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
241 : :
242 : 15 : gobject_class->dispose = g_inet_socket_address_dispose;
243 : 15 : gobject_class->set_property = g_inet_socket_address_set_property;
244 : 15 : gobject_class->get_property = g_inet_socket_address_get_property;
245 : :
246 : 15 : gsocketaddress_class->get_family = g_inet_socket_address_get_family;
247 : 15 : gsocketaddress_class->to_native = g_inet_socket_address_to_native;
248 : 15 : 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 : 15 : 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 : 15 : 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 : : * If unset this property is inherited from [property@Gio.InetSocketAddress:address].
286 : : *
287 : : * Since: 2.32
288 : : */
289 : 15 : g_object_class_install_property (gobject_class, PROP_FLOWINFO,
290 : : g_param_spec_uint ("flowinfo", NULL, NULL,
291 : : 0,
292 : : G_MAXUINT32,
293 : : 0,
294 : : G_PARAM_CONSTRUCT_ONLY |
295 : : G_PARAM_READWRITE |
296 : : G_PARAM_STATIC_STRINGS));
297 : :
298 : : /**
299 : : * GInetSocketAddress:scope-id:
300 : : *
301 : : * The `sin6_scope_id` field, for IPv6 addresses.
302 : : *
303 : : * If unset this property is inherited from [property@Gio.InetSocketAddress:address].
304 : : *
305 : : * Since: 2.32
306 : : */
307 : 15 : g_object_class_install_property (gobject_class, PROP_SCOPE_ID,
308 : : g_param_spec_uint ("scope-id", NULL, NULL,
309 : : 0,
310 : : G_MAXUINT32,
311 : : 0,
312 : : G_PARAM_CONSTRUCT_ONLY |
313 : : G_PARAM_READWRITE |
314 : : G_PARAM_STATIC_STRINGS));
315 : 15 : }
316 : :
317 : : static void
318 : 15 : g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
319 : : {
320 : 15 : GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
321 : :
322 : 15 : iface->enumerate = parent_iface->enumerate;
323 : 15 : iface->proxy_enumerate = parent_iface->proxy_enumerate;
324 : 15 : iface->to_string = g_inet_socket_address_connectable_to_string;
325 : 15 : }
326 : :
327 : : static gchar *
328 : 4 : g_inet_socket_address_connectable_to_string (GSocketConnectable *connectable)
329 : : {
330 : : GInetSocketAddress *sa;
331 : : GInetAddress *a;
332 : : gchar *a_string;
333 : : GString *out;
334 : : guint16 port;
335 : :
336 : 4 : sa = G_INET_SOCKET_ADDRESS (connectable);
337 : 4 : a = g_inet_socket_address_get_address (sa);
338 : 4 : out = g_string_new ("");
339 : :
340 : : /* Address. */
341 : 4 : a_string = g_inet_address_to_string (a);
342 : : g_string_append (out, a_string);
343 : 4 : g_free (a_string);
344 : :
345 : : /* Scope ID (IPv6 only). */
346 : 7 : if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6 &&
347 : 3 : g_inet_socket_address_get_scope_id (sa) != 0)
348 : : {
349 : 1 : g_string_append_printf (out, "%%%u",
350 : : g_inet_socket_address_get_scope_id (sa));
351 : : }
352 : :
353 : : /* Port. */
354 : 4 : port = g_inet_socket_address_get_port (sa);
355 : 4 : if (port != 0)
356 : : {
357 : : /* Disambiguate ports from IPv6 addresses using square brackets. */
358 : 3 : if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6)
359 : : {
360 : 2 : g_string_prepend (out, "[");
361 : 4 : g_string_append (out, "]");
362 : : }
363 : :
364 : 3 : g_string_append_printf (out, ":%u", port);
365 : : }
366 : :
367 : 4 : return g_string_free (out, FALSE);
368 : : }
369 : :
370 : : static void
371 : 565 : g_inet_socket_address_init (GInetSocketAddress *address)
372 : : {
373 : 565 : address->priv = g_inet_socket_address_get_instance_private (address);
374 : 565 : }
375 : :
376 : : /**
377 : : * g_inet_socket_address_new:
378 : : * @address: a #GInetAddress
379 : : * @port: a port number
380 : : *
381 : : * Creates a new #GInetSocketAddress for @address and @port.
382 : : *
383 : : * Returns: a new #GInetSocketAddress
384 : : *
385 : : * Since: 2.22
386 : : */
387 : : GSocketAddress *
388 : 510 : g_inet_socket_address_new (GInetAddress *address,
389 : : guint16 port)
390 : : {
391 : 510 : return g_object_new (G_TYPE_INET_SOCKET_ADDRESS,
392 : : "address", address,
393 : : "port", port,
394 : : NULL);
395 : : }
396 : :
397 : : /**
398 : : * g_inet_socket_address_new_from_string:
399 : : * @address: the string form of an IP address
400 : : * @port: a port number
401 : : *
402 : : * Creates a new #GInetSocketAddress for @address and @port.
403 : : *
404 : : * If @address is an IPv6 address, it can also contain a scope ID
405 : : * (separated from the address by a `%`). Note that currently this
406 : : * behavior is platform specific. This may change in a future release.
407 : : *
408 : : * Returns: (nullable) (transfer full): a new #GInetSocketAddress,
409 : : * or %NULL if @address cannot be parsed.
410 : : *
411 : : * Since: 2.40
412 : : */
413 : : GSocketAddress *
414 : 148 : g_inet_socket_address_new_from_string (const char *address,
415 : : guint port)
416 : : {
417 : : GSocketAddress *saddr;
418 : : GInetAddress *iaddr;
419 : :
420 : 148 : iaddr = g_inet_address_new_from_string (address);
421 : 148 : if (!iaddr)
422 : 80 : return NULL;
423 : :
424 : 68 : saddr = g_inet_socket_address_new (iaddr, port);
425 : :
426 : 68 : g_object_unref (iaddr);
427 : 68 : return saddr;
428 : : }
429 : :
430 : : /**
431 : : * g_inet_socket_address_get_address:
432 : : * @address: a #GInetSocketAddress
433 : : *
434 : : * Gets @address's #GInetAddress.
435 : : *
436 : : * Returns: (transfer none): the #GInetAddress for @address, which must be
437 : : * g_object_ref()'d if it will be stored
438 : : *
439 : : * Since: 2.22
440 : : */
441 : : GInetAddress *
442 : 676 : g_inet_socket_address_get_address (GInetSocketAddress *address)
443 : : {
444 : 676 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), NULL);
445 : :
446 : 676 : return address->priv->address;
447 : : }
448 : :
449 : : /**
450 : : * g_inet_socket_address_get_port:
451 : : * @address: a #GInetSocketAddress
452 : : *
453 : : * Gets @address's port.
454 : : *
455 : : * Returns: the port for @address
456 : : *
457 : : * Since: 2.22
458 : : */
459 : : guint16
460 : 111 : g_inet_socket_address_get_port (GInetSocketAddress *address)
461 : : {
462 : 111 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
463 : :
464 : 111 : return address->priv->port;
465 : : }
466 : :
467 : :
468 : : /**
469 : : * g_inet_socket_address_get_flowinfo:
470 : : * @address: a %G_SOCKET_FAMILY_IPV6 #GInetSocketAddress
471 : : *
472 : : * Gets the `sin6_flowinfo` field from @address,
473 : : * which must be an IPv6 address.
474 : : *
475 : : * If not overridden this value will be inherited from [property@Gio.InetSocketAddress:address].
476 : : *
477 : : * Returns: the flowinfo field
478 : : *
479 : : * Since: 2.32
480 : : */
481 : : guint32
482 : 64 : g_inet_socket_address_get_flowinfo (GInetSocketAddress *address)
483 : : {
484 : 64 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
485 : 64 : g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0);
486 : :
487 : 64 : return address->priv->flowinfo ? address->priv->flowinfo : g_inet_address_get_flowinfo (address->priv->address);
488 : : }
489 : :
490 : : /**
491 : : * g_inet_socket_address_get_scope_id:
492 : : * @address: a %G_SOCKET_FAMILY_IPV6 #GInetAddress
493 : : *
494 : : * Gets the `sin6_scope_id` field from @address,
495 : : * which must be an IPv6 address.
496 : : *
497 : : * If not overridden this value will be inherited from [property@Gio.InetSocketAddress:address].
498 : : *
499 : : * Returns: the scope id field
500 : : *
501 : : * Since: 2.32
502 : : */
503 : : guint32
504 : 74 : g_inet_socket_address_get_scope_id (GInetSocketAddress *address)
505 : : {
506 : 74 : g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
507 : 74 : g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0);
508 : :
509 : 74 : return address->priv->scope_id ? address->priv->scope_id : g_inet_address_get_scope_id (address->priv->address);
510 : : }
|