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 "gsocketaddress.h"
29 : : #include "ginetaddress.h"
30 : : #include "ginetsocketaddress.h"
31 : : #include "gnativesocketaddress.h"
32 : : #include "gnetworkingprivate.h"
33 : : #include "gproxyaddress.h"
34 : : #include "gproxyaddressenumerator.h"
35 : : #include "gsocketaddressenumerator.h"
36 : : #include "gsocketconnectable.h"
37 : : #include "glibintl.h"
38 : : #include "gioenumtypes.h"
39 : :
40 : : #include "gunixsocketaddress.h"
41 : :
42 : : #ifdef G_OS_WIN32
43 : : #include "giowin32-afunix.h"
44 : : #endif
45 : :
46 : :
47 : : /**
48 : : * GSocketAddress:
49 : : *
50 : : * `GSocketAddress` is the equivalent of
51 : : * [`struct sockaddr`](man:sockaddr(3type)) and its subtypes in the BSD sockets
52 : : * API. This is an abstract class; use [class@Gio.InetSocketAddress] for
53 : : * internet sockets, or [class@Gio.UnixSocketAddress] for UNIX domain sockets.
54 : : */
55 : :
56 : : enum
57 : : {
58 : : PROP_NONE,
59 : : PROP_FAMILY
60 : : };
61 : :
62 : : static void g_socket_address_connectable_iface_init (GSocketConnectableIface *iface);
63 : : static GSocketAddressEnumerator *g_socket_address_connectable_enumerate (GSocketConnectable *connectable);
64 : : static GSocketAddressEnumerator *g_socket_address_connectable_proxy_enumerate (GSocketConnectable *connectable);
65 : :
66 : 300331 : G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GSocketAddress, g_socket_address, G_TYPE_OBJECT,
67 : : G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
68 : : g_socket_address_connectable_iface_init))
69 : :
70 : : /**
71 : : * g_socket_address_get_family:
72 : : * @address: a #GSocketAddress
73 : : *
74 : : * Gets the socket family type of @address.
75 : : *
76 : : * Returns: the socket family type of @address
77 : : *
78 : : * Since: 2.22
79 : : */
80 : : GSocketFamily
81 : 1641 : g_socket_address_get_family (GSocketAddress *address)
82 : : {
83 : 1641 : g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), 0);
84 : :
85 : 1641 : return G_SOCKET_ADDRESS_GET_CLASS (address)->get_family (address);
86 : : }
87 : :
88 : : static void
89 : 1 : g_socket_address_get_property (GObject *object, guint prop_id,
90 : : GValue *value, GParamSpec *pspec)
91 : : {
92 : 1 : GSocketAddress *address = G_SOCKET_ADDRESS (object);
93 : :
94 : 1 : switch (prop_id)
95 : : {
96 : 1 : case PROP_FAMILY:
97 : 1 : g_value_set_enum (value, g_socket_address_get_family (address));
98 : 1 : break;
99 : :
100 : 0 : default:
101 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
102 : : }
103 : 1 : }
104 : :
105 : : static void
106 : 147 : g_socket_address_class_init (GSocketAddressClass *klass)
107 : : {
108 : 147 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
109 : :
110 : 147 : gobject_class->get_property = g_socket_address_get_property;
111 : :
112 : : /**
113 : : * GSocketAddress:family:
114 : : *
115 : : * The family of the socket address.
116 : : *
117 : : * Since: 2.22
118 : : */
119 : 147 : g_object_class_install_property (gobject_class, PROP_FAMILY,
120 : : g_param_spec_enum ("family", NULL, NULL,
121 : : G_TYPE_SOCKET_FAMILY,
122 : : G_SOCKET_FAMILY_INVALID,
123 : : G_PARAM_READABLE |
124 : : G_PARAM_STATIC_STRINGS));
125 : 147 : }
126 : :
127 : : static void
128 : 147 : g_socket_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
129 : : {
130 : 147 : connectable_iface->enumerate = g_socket_address_connectable_enumerate;
131 : 147 : connectable_iface->proxy_enumerate = g_socket_address_connectable_proxy_enumerate;
132 : : /* to_string() is implemented by subclasses */
133 : 147 : }
134 : :
135 : : static void
136 : 2201 : g_socket_address_init (GSocketAddress *address)
137 : : {
138 : :
139 : 2201 : }
140 : :
141 : : /**
142 : : * g_socket_address_get_native_size:
143 : : * @address: a #GSocketAddress
144 : : *
145 : : * Gets the size of @address's native struct sockaddr.
146 : : * You can use this to allocate memory to pass to
147 : : * g_socket_address_to_native().
148 : : *
149 : : * Returns: the size of the native struct sockaddr that
150 : : * @address represents, or `-1` if @address
151 : : * is not valid
152 : : *
153 : : * Since: 2.22
154 : : */
155 : : gssize
156 : 1760 : g_socket_address_get_native_size (GSocketAddress *address)
157 : : {
158 : 1760 : g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), -1);
159 : :
160 : 1760 : return G_SOCKET_ADDRESS_GET_CLASS (address)->get_native_size (address);
161 : : }
162 : :
163 : : /**
164 : : * g_socket_address_to_native:
165 : : * @address: a #GSocketAddress
166 : : * @dest: a pointer to a memory location that will contain the native
167 : : * struct sockaddr
168 : : * @destlen: the size of @dest. Must be at least as large as
169 : : * g_socket_address_get_native_size()
170 : : * @error: #GError for error reporting, or %NULL to ignore
171 : : *
172 : : * Converts a #GSocketAddress to a native struct sockaddr, which can
173 : : * be passed to low-level functions like connect() or bind().
174 : : *
175 : : * If not enough space is available, a %G_IO_ERROR_NO_SPACE error
176 : : * is returned. If the address type is not known on the system
177 : : * then a %G_IO_ERROR_NOT_SUPPORTED error is returned.
178 : : *
179 : : * Returns: %TRUE if @dest was filled in, %FALSE on error
180 : : *
181 : : * Since: 2.22
182 : : */
183 : : gboolean
184 : 1852 : g_socket_address_to_native (GSocketAddress *address,
185 : : gpointer dest,
186 : : gsize destlen,
187 : : GError **error)
188 : : {
189 : 1852 : g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
190 : :
191 : 1852 : return G_SOCKET_ADDRESS_GET_CLASS (address)->to_native (address, dest, destlen, error);
192 : : }
193 : :
194 : : /**
195 : : * g_socket_address_new_from_native:
196 : : * @native: (not nullable): a pointer to a struct sockaddr
197 : : * @len: the size of the memory location pointed to by @native
198 : : *
199 : : * Creates a #GSocketAddress subclass corresponding to the native
200 : : * struct sockaddr @native.
201 : : *
202 : : * Returns: a new #GSocketAddress if @native could successfully
203 : : * be converted, otherwise %NULL
204 : : *
205 : : * Since: 2.22
206 : : */
207 : : GSocketAddress *
208 : 120 : g_socket_address_new_from_native (gpointer native,
209 : : gsize len)
210 : : {
211 : : #ifdef G_OS_WIN32
212 : : ADDRESS_FAMILY family;
213 : : #else
214 : : sa_family_t family;
215 : : #endif
216 : :
217 : 120 : if (len < sizeof (family))
218 : 0 : return NULL;
219 : :
220 : 120 : family = ((struct sockaddr *) native)->sa_family;
221 : :
222 : 120 : if (family == AF_UNSPEC)
223 : 0 : return NULL;
224 : :
225 : 120 : if (family == AF_INET)
226 : : {
227 : 46 : struct sockaddr_in *addr = (struct sockaddr_in *) native;
228 : : GInetAddress *iaddr;
229 : : GSocketAddress *sockaddr;
230 : :
231 : 46 : if (len < sizeof (*addr))
232 : 0 : return NULL;
233 : :
234 : 46 : iaddr = g_inet_address_new_from_bytes ((guint8 *) &(addr->sin_addr), G_SOCKET_FAMILY_IPV4);
235 : 46 : sockaddr = g_inet_socket_address_new (iaddr, g_ntohs (addr->sin_port));
236 : 46 : g_object_unref (iaddr);
237 : 46 : return sockaddr;
238 : : }
239 : :
240 : 74 : if (family == AF_INET6)
241 : : {
242 : 29 : struct sockaddr_in6 *addr = (struct sockaddr_in6 *) native;
243 : : GInetAddress *iaddr;
244 : : GSocketAddress *sockaddr;
245 : :
246 : 29 : if (len < sizeof (*addr))
247 : 0 : return NULL;
248 : :
249 : 29 : if (IN6_IS_ADDR_V4MAPPED (&(addr->sin6_addr)))
250 : : {
251 : : struct sockaddr_in sin_addr;
252 : :
253 : 2 : sin_addr.sin_family = AF_INET;
254 : 2 : sin_addr.sin_port = addr->sin6_port;
255 : 2 : memcpy (&(sin_addr.sin_addr.s_addr), addr->sin6_addr.s6_addr + 12, 4);
256 : 2 : iaddr = g_inet_address_new_from_bytes ((guint8 *) &(sin_addr.sin_addr), G_SOCKET_FAMILY_IPV4);
257 : : }
258 : : else
259 : : {
260 : 27 : iaddr = g_inet_address_new_from_bytes_with_ipv6_info ((guint8 *) &(addr->sin6_addr), G_SOCKET_FAMILY_IPV6, addr->sin6_flowinfo, addr->sin6_scope_id);
261 : : }
262 : :
263 : 29 : sockaddr = g_object_new (G_TYPE_INET_SOCKET_ADDRESS,
264 : : "address", iaddr,
265 : 29 : "port", g_ntohs (addr->sin6_port),
266 : : NULL);
267 : 29 : g_object_unref (iaddr);
268 : 29 : return sockaddr;
269 : : }
270 : :
271 : 45 : if (family == AF_UNIX)
272 : : {
273 : 1 : struct sockaddr_un *addr = (struct sockaddr_un *) native;
274 : 1 : gint path_len = len - G_STRUCT_OFFSET (struct sockaddr_un, sun_path);
275 : :
276 : 1 : if (path_len == 0)
277 : : {
278 : 1 : return g_unix_socket_address_new_with_type ("", 0,
279 : : G_UNIX_SOCKET_ADDRESS_ANONYMOUS);
280 : : }
281 : 0 : else if (addr->sun_path[0] == 0)
282 : : {
283 : 0 : if (!g_unix_socket_address_abstract_names_supported ())
284 : : {
285 : 0 : return g_unix_socket_address_new_with_type ("", 0,
286 : : G_UNIX_SOCKET_ADDRESS_ANONYMOUS);
287 : : }
288 : 0 : else if (len < sizeof (*addr))
289 : : {
290 : 0 : return g_unix_socket_address_new_with_type (addr->sun_path + 1,
291 : : path_len - 1,
292 : : G_UNIX_SOCKET_ADDRESS_ABSTRACT);
293 : : }
294 : : else
295 : : {
296 : 0 : return g_unix_socket_address_new_with_type (addr->sun_path + 1,
297 : : path_len - 1,
298 : : G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
299 : : }
300 : : }
301 : : else
302 : 0 : return g_unix_socket_address_new (addr->sun_path);
303 : : }
304 : :
305 : 44 : return g_native_socket_address_new (native, len);
306 : : }
307 : :
308 : :
309 : : #define G_TYPE_SOCKET_ADDRESS_ADDRESS_ENUMERATOR (_g_socket_address_address_enumerator_get_type ())
310 : : #define G_SOCKET_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_SOCKET_ADDRESS_ADDRESS_ENUMERATOR, GSocketAddressAddressEnumerator))
311 : :
312 : : typedef struct {
313 : : GSocketAddressEnumerator parent_instance;
314 : :
315 : : GSocketAddress *sockaddr;
316 : : } GSocketAddressAddressEnumerator;
317 : :
318 : : typedef struct {
319 : : GSocketAddressEnumeratorClass parent_class;
320 : :
321 : : } GSocketAddressAddressEnumeratorClass;
322 : :
323 : : static GType _g_socket_address_address_enumerator_get_type (void);
324 : 6377 : G_DEFINE_TYPE (GSocketAddressAddressEnumerator, _g_socket_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
325 : :
326 : : static void
327 : 1984 : g_socket_address_address_enumerator_finalize (GObject *object)
328 : : {
329 : : GSocketAddressAddressEnumerator *sockaddr_enum =
330 : 1984 : G_SOCKET_ADDRESS_ADDRESS_ENUMERATOR (object);
331 : :
332 : 1984 : if (sockaddr_enum->sockaddr)
333 : 0 : g_object_unref (sockaddr_enum->sockaddr);
334 : :
335 : 1984 : G_OBJECT_CLASS (_g_socket_address_address_enumerator_parent_class)->finalize (object);
336 : 1984 : }
337 : :
338 : : static GSocketAddress *
339 : 2163 : g_socket_address_address_enumerator_next (GSocketAddressEnumerator *enumerator,
340 : : GCancellable *cancellable,
341 : : GError **error)
342 : : {
343 : : GSocketAddressAddressEnumerator *sockaddr_enum =
344 : 2163 : G_SOCKET_ADDRESS_ADDRESS_ENUMERATOR (enumerator);
345 : :
346 : 2163 : if (sockaddr_enum->sockaddr)
347 : : {
348 : 1984 : GSocketAddress *ret = sockaddr_enum->sockaddr;
349 : :
350 : 1984 : sockaddr_enum->sockaddr = NULL;
351 : 1984 : return ret;
352 : : }
353 : : else
354 : 179 : return NULL;
355 : : }
356 : :
357 : : static void
358 : 1984 : _g_socket_address_address_enumerator_init (GSocketAddressAddressEnumerator *enumerator)
359 : : {
360 : 1984 : }
361 : :
362 : : static void
363 : 123 : _g_socket_address_address_enumerator_class_init (GSocketAddressAddressEnumeratorClass *sockaddrenum_class)
364 : : {
365 : 123 : GObjectClass *object_class = G_OBJECT_CLASS (sockaddrenum_class);
366 : : GSocketAddressEnumeratorClass *enumerator_class =
367 : 123 : G_SOCKET_ADDRESS_ENUMERATOR_CLASS (sockaddrenum_class);
368 : :
369 : 123 : enumerator_class->next = g_socket_address_address_enumerator_next;
370 : 123 : object_class->finalize = g_socket_address_address_enumerator_finalize;
371 : 123 : }
372 : :
373 : : static GSocketAddressEnumerator *
374 : 1984 : g_socket_address_connectable_enumerate (GSocketConnectable *connectable)
375 : : {
376 : : GSocketAddressAddressEnumerator *sockaddr_enum;
377 : :
378 : 1984 : sockaddr_enum = g_object_new (G_TYPE_SOCKET_ADDRESS_ADDRESS_ENUMERATOR, NULL);
379 : 1984 : sockaddr_enum->sockaddr = g_object_ref (G_SOCKET_ADDRESS (connectable));
380 : :
381 : 1984 : return (GSocketAddressEnumerator *)sockaddr_enum;
382 : : }
383 : :
384 : : static GSocketAddressEnumerator *
385 : 430 : g_socket_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
386 : : {
387 : 430 : GSocketAddressEnumerator *addr_enum = NULL;
388 : :
389 : 430 : g_assert (connectable != NULL);
390 : :
391 : 430 : if (G_IS_INET_SOCKET_ADDRESS (connectable) &&
392 : 424 : !G_IS_PROXY_ADDRESS (connectable))
393 : 424 : {
394 : : GInetAddress *addr;
395 : : guint port;
396 : : gchar *uri;
397 : : gchar *ip;
398 : :
399 : 424 : g_object_get (connectable, "address", &addr, "port", &port, NULL);
400 : :
401 : 424 : ip = g_inet_address_to_string (addr);
402 : 424 : uri = g_uri_join (G_URI_FLAGS_NONE, "none", NULL, ip, port, "", NULL, NULL);
403 : :
404 : 424 : addr_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
405 : : "connectable", connectable,
406 : : "uri", uri,
407 : : NULL);
408 : :
409 : 424 : g_object_unref (addr);
410 : 424 : g_free (ip);
411 : 424 : g_free (uri);
412 : : }
413 : : else
414 : : {
415 : 6 : addr_enum = g_socket_address_connectable_enumerate (connectable);
416 : : }
417 : :
418 : 430 : return addr_enum;
419 : : }
|