• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
g_inet_socket_address_dispose(GObject * object)75 g_inet_socket_address_dispose (GObject *object)
76 {
77   GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
78 
79   g_clear_object (&(address->priv->address));
80 
81   G_OBJECT_CLASS (g_inet_socket_address_parent_class)->dispose (object);
82 }
83 
84 static void
g_inet_socket_address_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)85 g_inet_socket_address_get_property (GObject    *object,
86                                     guint       prop_id,
87                                     GValue     *value,
88                                     GParamSpec *pspec)
89 {
90   GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
91 
92   switch (prop_id)
93     {
94       case PROP_ADDRESS:
95         g_value_set_object (value, address->priv->address);
96         break;
97 
98       case PROP_PORT:
99         g_value_set_uint (value, address->priv->port);
100         break;
101 
102       case PROP_FLOWINFO:
103 	g_return_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6);
104         g_value_set_uint (value, address->priv->flowinfo);
105         break;
106 
107       case PROP_SCOPE_ID:
108 	g_return_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6);
109         g_value_set_uint (value, address->priv->scope_id);
110         break;
111 
112       default:
113         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
114     }
115 }
116 
117 static void
g_inet_socket_address_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)118 g_inet_socket_address_set_property (GObject      *object,
119                                     guint         prop_id,
120                                     const GValue *value,
121                                     GParamSpec   *pspec)
122 {
123   GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (object);
124 
125   switch (prop_id)
126     {
127       case PROP_ADDRESS:
128         address->priv->address = g_object_ref (g_value_get_object (value));
129         break;
130 
131       case PROP_PORT:
132         address->priv->port = (guint16) g_value_get_uint (value);
133         break;
134 
135       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         address->priv->flowinfo = g_value_get_uint (value);
140         break;
141 
142       case PROP_SCOPE_ID:
143         address->priv->scope_id = g_value_get_uint (value);
144         break;
145 
146       default:
147         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
148     }
149 }
150 
151 static GSocketFamily
g_inet_socket_address_get_family(GSocketAddress * address)152 g_inet_socket_address_get_family (GSocketAddress *address)
153 {
154   GInetSocketAddress *addr;
155 
156   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
157 
158   addr = G_INET_SOCKET_ADDRESS (address);
159 
160   return g_inet_address_get_family (addr->priv->address);
161 }
162 
163 static gssize
g_inet_socket_address_get_native_size(GSocketAddress * address)164 g_inet_socket_address_get_native_size (GSocketAddress *address)
165 {
166   GInetSocketAddress *addr;
167   GSocketFamily family;
168 
169   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
170 
171   addr = G_INET_SOCKET_ADDRESS (address);
172   family = g_inet_address_get_family (addr->priv->address);
173 
174   if (family == AF_INET)
175     return sizeof (struct sockaddr_in);
176   else if (family == AF_INET6)
177     return sizeof (struct sockaddr_in6);
178   else
179     return -1;
180 }
181 
182 static gboolean
g_inet_socket_address_to_native(GSocketAddress * address,gpointer dest,gsize destlen,GError ** error)183 g_inet_socket_address_to_native (GSocketAddress  *address,
184                                  gpointer         dest,
185 				 gsize            destlen,
186 				 GError         **error)
187 {
188   GInetSocketAddress *addr;
189   GSocketFamily family;
190 
191   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), FALSE);
192 
193   addr = G_INET_SOCKET_ADDRESS (address);
194   family = g_inet_address_get_family (addr->priv->address);
195 
196   if (family == AF_INET)
197     {
198       struct sockaddr_in *sock = (struct sockaddr_in *) dest;
199 
200       if (destlen < sizeof (*sock))
201 	{
202 	  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
203 			       _("Not enough space for socket address"));
204 	  return FALSE;
205 	}
206 
207       sock->sin_family = AF_INET;
208       sock->sin_port = g_htons (addr->priv->port);
209       memcpy (&(sock->sin_addr.s_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin_addr));
210       memset (sock->sin_zero, 0, sizeof (sock->sin_zero));
211       return TRUE;
212     }
213   else if (family == AF_INET6)
214     {
215       struct sockaddr_in6 *sock = (struct sockaddr_in6 *) dest;
216 
217       if (destlen < sizeof (*sock))
218 	{
219 	  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
220 			       _("Not enough space for socket address"));
221 	  return FALSE;
222 	}
223 
224       memset (sock, 0, sizeof (*sock));
225       sock->sin6_family = AF_INET6;
226       sock->sin6_port = g_htons (addr->priv->port);
227       sock->sin6_flowinfo = addr->priv->flowinfo;
228       sock->sin6_scope_id = addr->priv->scope_id;
229       memcpy (&(sock->sin6_addr.s6_addr), g_inet_address_to_bytes (addr->priv->address), sizeof (sock->sin6_addr));
230       return TRUE;
231     }
232   else
233     {
234       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
235 			   _("Unsupported socket address"));
236       return FALSE;
237     }
238 }
239 
240 static void
g_inet_socket_address_class_init(GInetSocketAddressClass * klass)241 g_inet_socket_address_class_init (GInetSocketAddressClass *klass)
242 {
243   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
244   GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
245 
246   gobject_class->dispose = g_inet_socket_address_dispose;
247   gobject_class->set_property = g_inet_socket_address_set_property;
248   gobject_class->get_property = g_inet_socket_address_get_property;
249 
250   gsocketaddress_class->get_family = g_inet_socket_address_get_family;
251   gsocketaddress_class->to_native = g_inet_socket_address_to_native;
252   gsocketaddress_class->get_native_size = g_inet_socket_address_get_native_size;
253 
254   g_object_class_install_property (gobject_class, PROP_ADDRESS,
255                                    g_param_spec_object ("address",
256                                                         P_("Address"),
257                                                         P_("The address"),
258                                                         G_TYPE_INET_ADDRESS,
259                                                         G_PARAM_CONSTRUCT_ONLY |
260                                                         G_PARAM_READWRITE |
261                                                         G_PARAM_STATIC_STRINGS));
262 
263   g_object_class_install_property (gobject_class, PROP_PORT,
264                                    g_param_spec_uint ("port",
265                                                       P_("Port"),
266                                                       P_("The port"),
267                                                       0,
268                                                       65535,
269                                                       0,
270                                                       G_PARAM_CONSTRUCT_ONLY |
271                                                       G_PARAM_READWRITE |
272                                                       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   g_object_class_install_property (gobject_class, PROP_FLOWINFO,
282                                    g_param_spec_uint ("flowinfo",
283                                                       P_("Flow info"),
284                                                       P_("IPv6 flow info"),
285                                                       0,
286                                                       G_MAXUINT32,
287                                                       0,
288                                                       G_PARAM_CONSTRUCT_ONLY |
289                                                       G_PARAM_READWRITE |
290                                                       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   g_object_class_install_property (gobject_class, PROP_SCOPE_ID,
300                                    g_param_spec_uint ("scope-id",
301                                                       P_("Scope ID"),
302                                                       P_("IPv6 scope ID"),
303                                                       0,
304                                                       G_MAXUINT32,
305                                                       0,
306                                                       G_PARAM_CONSTRUCT_ONLY |
307                                                       G_PARAM_READWRITE |
308                                                       G_PARAM_STATIC_STRINGS));
309 }
310 
311 static void
g_inet_socket_address_connectable_iface_init(GSocketConnectableIface * iface)312 g_inet_socket_address_connectable_iface_init (GSocketConnectableIface *iface)
313 {
314   GSocketConnectableIface *parent_iface = g_type_interface_peek_parent (iface);
315 
316   iface->enumerate = parent_iface->enumerate;
317   iface->proxy_enumerate = parent_iface->proxy_enumerate;
318   iface->to_string = g_inet_socket_address_connectable_to_string;
319 }
320 
321 static gchar *
g_inet_socket_address_connectable_to_string(GSocketConnectable * connectable)322 g_inet_socket_address_connectable_to_string (GSocketConnectable *connectable)
323 {
324   GInetSocketAddress *sa;
325   GInetAddress *a;
326   gchar *a_string;
327   GString *out;
328   guint16 port;
329 
330   sa = G_INET_SOCKET_ADDRESS (connectable);
331   a = g_inet_socket_address_get_address (sa);
332   out = g_string_new ("");
333 
334   /* Address. */
335   a_string = g_inet_address_to_string (a);
336   g_string_append (out, a_string);
337   g_free (a_string);
338 
339   /* Scope ID (IPv6 only). */
340   if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6 &&
341       g_inet_socket_address_get_scope_id (sa) != 0)
342     {
343       g_string_append_printf (out, "%%%u",
344                               g_inet_socket_address_get_scope_id (sa));
345     }
346 
347   /* Port. */
348   port = g_inet_socket_address_get_port (sa);
349   if (port != 0)
350     {
351       /* Disambiguate ports from IPv6 addresses using square brackets. */
352       if (g_inet_address_get_family (a) == G_SOCKET_FAMILY_IPV6)
353         {
354           g_string_prepend (out, "[");
355           g_string_append (out, "]");
356         }
357 
358       g_string_append_printf (out, ":%u", port);
359     }
360 
361   return g_string_free (out, FALSE);
362 }
363 
364 static void
g_inet_socket_address_init(GInetSocketAddress * address)365 g_inet_socket_address_init (GInetSocketAddress *address)
366 {
367   address->priv = g_inet_socket_address_get_instance_private (address);
368 }
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 *
g_inet_socket_address_new(GInetAddress * address,guint16 port)382 g_inet_socket_address_new (GInetAddress *address,
383                            guint16       port)
384 {
385   return g_object_new (G_TYPE_INET_SOCKET_ADDRESS,
386 		       "address", address,
387 		       "port", port,
388 		       NULL);
389 }
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 *
g_inet_socket_address_new_from_string(const char * address,guint port)407 g_inet_socket_address_new_from_string (const char *address,
408                                        guint       port)
409 {
410   static struct addrinfo *hints, hints_struct;
411   GSocketAddress *saddr;
412   GInetAddress *iaddr;
413   struct addrinfo *res;
414   gint status;
415 
416   if (strchr (address, ':'))
417     {
418       /* IPv6 address (or it's invalid). We use getaddrinfo() because
419        * it will handle parsing a scope_id as well.
420        */
421 
422       if (G_UNLIKELY (g_once_init_enter (&hints)))
423         {
424           hints_struct.ai_family = AF_UNSPEC;
425           hints_struct.ai_socktype = SOCK_STREAM;
426           hints_struct.ai_protocol = 0;
427           hints_struct.ai_flags = AI_NUMERICHOST;
428           g_once_init_leave (&hints, &hints_struct);
429         }
430 
431       status = getaddrinfo (address, NULL, hints, &res);
432       if (status != 0)
433         return NULL;
434 
435       if (res->ai_family == AF_INET6 &&
436           res->ai_addrlen == sizeof (struct sockaddr_in6))
437         {
438           ((struct sockaddr_in6 *)res->ai_addr)->sin6_port = g_htons (port);
439           saddr = g_socket_address_new_from_native (res->ai_addr, res->ai_addrlen);
440         }
441       else
442         saddr = NULL;
443 
444       freeaddrinfo (res);
445     }
446   else
447     {
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       iaddr = g_inet_address_new_from_string (address);
455       if (!iaddr)
456         return NULL;
457 
458       g_warn_if_fail (g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV4);
459 
460       saddr = g_inet_socket_address_new (iaddr, port);
461       g_object_unref (iaddr);
462     }
463 
464   return saddr;
465 }
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 *
g_inet_socket_address_get_address(GInetSocketAddress * address)479 g_inet_socket_address_get_address (GInetSocketAddress *address)
480 {
481   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), NULL);
482 
483   return address->priv->address;
484 }
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
g_inet_socket_address_get_port(GInetSocketAddress * address)497 g_inet_socket_address_get_port (GInetSocketAddress *address)
498 {
499   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
500 
501   return address->priv->port;
502 }
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
g_inet_socket_address_get_flowinfo(GInetSocketAddress * address)517 g_inet_socket_address_get_flowinfo (GInetSocketAddress *address)
518 {
519   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
520   g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0);
521 
522   return address->priv->flowinfo;
523 }
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
g_inet_socket_address_get_scope_id(GInetSocketAddress * address)537 g_inet_socket_address_get_scope_id (GInetSocketAddress *address)
538 {
539   g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (address), 0);
540   g_return_val_if_fail (g_inet_address_get_family (address->priv->address) == G_SOCKET_FAMILY_IPV6, 0);
541 
542   return address->priv->scope_id;
543 }
544