Merge branch 'gdbus-merge'
[platform/upstream/glib.git] / gio / gunixsocketaddress.c
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 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
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 "gunixsocketaddress.h"
29 #include "glibintl.h"
30 #include "gnetworkingprivate.h"
31
32 #include "gioalias.h"
33
34 /**
35  * SECTION:gunixsocketaddress
36  * @short_description: UNIX GSocketAddress
37  * @include: gio/gunixsocketaddress.h
38  *
39  * Support for UNIX-domain (also known as local) sockets.
40  *
41  * UNIX domain sockets are generally visible in the filesystem.
42  * However, some systems support abstract socket names which are not
43  * visible in the filesystem and not affected by the filesystem
44  * permissions, visibility, etc. Currently this is only supported
45  * under Linux. If you attempt to use abstract sockets on other
46  * systems, function calls may return %G_IO_ERROR_NOT_SUPPORTED
47  * errors. You can use g_unix_socket_address_abstract_names_supported()
48  * to see if abstract names are supported.
49  *
50  * Note that <filename>&lt;gio/gunixsocketaddress.h&gt;</filename> belongs to
51  * the UNIX-specific GIO interfaces, thus you have to use the
52  * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
53  */
54
55 /**
56  * GUnixSocketAddress:
57  *
58  * A UNIX-domain (local) socket address, corresponding to a
59  * <type>struct sockaddr_un</type>.
60  */
61 G_DEFINE_TYPE (GUnixSocketAddress, g_unix_socket_address, G_TYPE_SOCKET_ADDRESS);
62
63 enum
64 {
65   PROP_0,
66   PROP_PATH,
67   PROP_PATH_AS_ARRAY,
68   PROP_ABSTRACT,
69   PROP_ADDRESS_TYPE
70 };
71
72 #define UNIX_PATH_MAX sizeof (((struct sockaddr_un *) 0)->sun_path)
73
74 struct _GUnixSocketAddressPrivate
75 {
76   char path[UNIX_PATH_MAX]; /* Not including the initial zero in abstract case, so
77                                we can guarantee zero termination of abstract
78                                pathnames in the get_path() API */
79   gsize path_len; /* Not including any terminating zeros */
80   GUnixSocketAddressType address_type;
81 };
82
83 static void
84 g_unix_socket_address_set_property (GObject      *object,
85                                     guint         prop_id,
86                                     const GValue *value,
87                                     GParamSpec   *pspec)
88 {
89   GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
90   const char *str;
91   GByteArray *array;
92   gsize len;
93
94   switch (prop_id)
95     {
96     case PROP_PATH:
97       str = g_value_get_string (value);
98       if (str)
99         {
100           g_strlcpy (address->priv->path, str,
101                      sizeof (address->priv->path));
102           address->priv->path_len = strlen (address->priv->path);
103         }
104       break;
105
106     case PROP_PATH_AS_ARRAY:
107       array = g_value_get_boxed (value);
108
109       if (array)
110         {
111           /* Clip to fit in UNIX_PATH_MAX with zero termination or first byte */
112           len = MIN (array->len, UNIX_PATH_MAX-1);
113
114           memcpy (address->priv->path, array->data, len);
115           address->priv->path[len] = 0; /* Ensure null-terminated */
116           address->priv->path_len = len;
117         }
118       break;
119
120     case PROP_ABSTRACT:
121       /* If the caller already set PROP_ADDRESS_TYPE, don't let the
122        * default value of PROP_ABSTRACT overwrite it.
123        */
124       if (address->priv->address_type != G_UNIX_SOCKET_ADDRESS_INVALID)
125         return;
126
127       if (g_value_get_boolean (value))
128         address->priv->address_type = G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED;
129       else
130         address->priv->address_type = G_UNIX_SOCKET_ADDRESS_PATH;
131       break;
132
133     case PROP_ADDRESS_TYPE:
134       /* If the caller already set PROP_ABSTRACT, don't let the
135        * default value of PROP_ADDRESS_TYPE overwrite it.
136        */
137       if (address->priv->address_type != G_UNIX_SOCKET_ADDRESS_INVALID)
138         return;
139
140       address->priv->address_type = g_value_get_enum (value);
141       break;
142
143     default:
144       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145     }
146 }
147
148 static void
149 g_unix_socket_address_get_property (GObject    *object,
150                                     guint       prop_id,
151                                     GValue     *value,
152                                     GParamSpec *pspec)
153 {
154   GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
155   GByteArray *array;
156
157   switch (prop_id)
158     {
159       case PROP_PATH:
160         g_value_set_string (value, address->priv->path);
161         break;
162
163       case PROP_PATH_AS_ARRAY:
164         array = g_byte_array_sized_new (address->priv->path_len);
165         g_byte_array_append (array, (guint8 *)address->priv->path, address->priv->path_len);
166         g_value_take_boxed (value, array);
167         break;
168
169       case PROP_ABSTRACT:
170         g_value_set_boolean (value, (address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT ||
171                                      address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED));
172
173         break;
174
175       case PROP_ADDRESS_TYPE:
176         g_value_set_enum (value, address->priv->address_type);
177         break;
178
179       default:
180         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181     }
182 }
183
184 static GSocketFamily
185 g_unix_socket_address_get_family (GSocketAddress *address)
186 {
187   g_assert (PF_UNIX == G_SOCKET_FAMILY_UNIX);
188
189   return G_SOCKET_FAMILY_UNIX;
190 }
191
192 static gssize
193 g_unix_socket_address_get_native_size (GSocketAddress *address)
194 {
195   GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
196
197   switch (addr->priv->address_type)
198     {
199     case G_UNIX_SOCKET_ADDRESS_ANONYMOUS:
200       return G_STRUCT_OFFSET(struct sockaddr_un, sun_path);
201     case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
202       return G_STRUCT_OFFSET(struct sockaddr_un, sun_path) + addr->priv->path_len + 1;
203     default:
204       return sizeof (struct sockaddr_un);
205     }
206 }
207
208 static gboolean
209 g_unix_socket_address_to_native (GSocketAddress *address,
210                                  gpointer        dest,
211                                  gsize           destlen,
212                                  GError        **error)
213 {
214   GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
215   struct sockaddr_un *sock;
216   gssize socklen;
217
218   socklen = g_unix_socket_address_get_native_size (address);
219   if (destlen < socklen)
220     {
221       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
222                            _("Not enough space for socket address"));
223       return FALSE;
224     }
225
226   sock = (struct sockaddr_un *) dest;
227   memset (sock, 0, socklen);
228   sock->sun_family = AF_UNIX;
229
230   switch (addr->priv->address_type)
231     {
232     case G_UNIX_SOCKET_ADDRESS_INVALID:
233     case G_UNIX_SOCKET_ADDRESS_ANONYMOUS:
234       break;
235
236     case G_UNIX_SOCKET_ADDRESS_PATH:
237       strcpy (sock->sun_path, addr->priv->path);
238       break;
239
240     case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
241     case G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED:
242       if (!g_unix_socket_address_abstract_names_supported ())
243         {
244           g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
245                                _("Abstract unix domain socket addresses not supported on this system"));
246           return FALSE;
247         }
248
249       sock->sun_path[0] = 0;
250       memcpy (sock->sun_path+1, addr->priv->path, addr->priv->path_len);
251       break;
252     }
253
254   return TRUE;
255 }
256
257 static void
258 g_unix_socket_address_class_init (GUnixSocketAddressClass *klass)
259 {
260   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
261   GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
262
263   g_type_class_add_private (klass, sizeof (GUnixSocketAddressPrivate));
264
265   gobject_class->set_property = g_unix_socket_address_set_property;
266   gobject_class->get_property = g_unix_socket_address_get_property;
267
268   gsocketaddress_class->get_family = g_unix_socket_address_get_family;
269   gsocketaddress_class->to_native = g_unix_socket_address_to_native;
270   gsocketaddress_class->get_native_size = g_unix_socket_address_get_native_size;
271
272   g_object_class_install_property (gobject_class,
273                                    PROP_PATH,
274                                    g_param_spec_string ("path",
275                                                         P_("Path"),
276                                                         P_("UNIX socket path"),
277                                                         NULL,
278                                                         G_PARAM_READWRITE |
279                                                         G_PARAM_CONSTRUCT_ONLY |
280                                                         G_PARAM_STATIC_STRINGS));
281   g_object_class_install_property (gobject_class, PROP_PATH_AS_ARRAY,
282                                    g_param_spec_boxed ("path-as-array",
283                                                        P_("Path array"),
284                                                        P_("UNIX socket path, as byte array"),
285                                                        G_TYPE_BYTE_ARRAY,
286                                                        G_PARAM_READWRITE |
287                                                        G_PARAM_CONSTRUCT_ONLY |
288                                                        G_PARAM_STATIC_STRINGS));
289   /**
290    * GUnixSocketAddress:abstract:
291    *
292    * Whether or not this is an abstract address
293    *
294    * Deprecated: Use #GUnixSocketAddress:address-type, which
295    * distinguishes between zero-padded and non-zero-padded
296    * abstract addresses.
297    */
298   g_object_class_install_property (gobject_class, PROP_ABSTRACT,
299                                    g_param_spec_boolean ("abstract",
300                                                          P_("Abstract"),
301                                                          P_("Whether or not this is an abstract address"),
302                                                          FALSE,
303                                                          G_PARAM_READWRITE |
304                                                          G_PARAM_CONSTRUCT_ONLY |
305                                                          G_PARAM_STATIC_STRINGS));
306   g_object_class_install_property (gobject_class, PROP_ADDRESS_TYPE,
307                                    g_param_spec_enum ("address-type",
308                                                       P_("Address type"),
309                                                       P_("The type of UNIX socket address"),
310                                                       G_TYPE_UNIX_SOCKET_ADDRESS_TYPE,
311                                                       G_UNIX_SOCKET_ADDRESS_PATH,
312                                                       G_PARAM_READWRITE |
313                                                       G_PARAM_CONSTRUCT_ONLY |
314                                                       G_PARAM_STATIC_STRINGS));
315 }
316
317 static void
318 g_unix_socket_address_init (GUnixSocketAddress *address)
319 {
320   address->priv = G_TYPE_INSTANCE_GET_PRIVATE (address,
321                                                G_TYPE_UNIX_SOCKET_ADDRESS,
322                                                GUnixSocketAddressPrivate);
323
324   memset (address->priv->path, 0, sizeof (address->priv->path));
325   address->priv->path_len = -1;
326   address->priv->address_type = G_UNIX_SOCKET_ADDRESS_INVALID;
327 }
328
329 /**
330  * g_unix_socket_address_new:
331  * @path: the socket path
332  *
333  * Creates a new #GUnixSocketAddress for @path.
334  *
335  * To create abstract socket addresses, on systems that support that,
336  * use g_unix_socket_address_new_abstract().
337  *
338  * Returns: a new #GUnixSocketAddress
339  *
340  * Since: 2.22
341  */
342 GSocketAddress *
343 g_unix_socket_address_new (const gchar *path)
344 {
345   return g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
346                        "path", path,
347                        "abstract", FALSE,
348                        NULL);
349 }
350
351 /**
352  * g_unix_socket_address_new_abstract:
353  * @path: the abstract name
354  * @path_len: the length of @path, or -1
355  *
356  * Creates a new %G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED
357  * #GUnixSocketAddress for @path.
358  *
359  * Returns: a new #GUnixSocketAddress
360  *
361  * Deprecated: Use g_unix_socket_address_new_with_type().
362  */
363 GSocketAddress *
364 g_unix_socket_address_new_abstract (const gchar *path,
365                                     gint         path_len)
366 {
367   return g_unix_socket_address_new_with_type (path, path_len,
368                                               G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
369 }
370
371 /**
372  * g_unix_socket_address_new_with_type:
373  * @path: the name
374  * @path_len: the length of @path, or -1
375  * @type: a #GUnixSocketAddressType
376  *
377  * Creates a new #GUnixSocketAddress of type @type with name @path.
378  *
379  * If @type is %G_UNIX_SOCKET_ADDRESS_PATH, this is equivalent to
380  * calling g_unix_socket_address_new().
381  *
382  * If @path_type is %G_UNIX_SOCKET_ADDRESS_ABSTRACT, then @path_len
383  * bytes of @path will be copied to the socket's path, and only those
384  * bytes will be considered part of the name. (If @path_len is -1,
385  * then @path is assumed to be NUL-terminated.) For example, if @path
386  * was "test", then calling g_socket_address_get_native_size() on the
387  * returned socket would return 7 (2 bytes of overhead, 1 byte for the
388  * abstract-socket indicator byte, and 4 bytes for the name "test").
389  *
390  * If @path_type is %G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED, then
391  * @path_len bytes of @path will be copied to the socket's path, the
392  * rest of the path will be padded with 0 bytes, and the entire
393  * zero-padded buffer will be considered the name. (As above, if
394  * @path_len is -1, then @path is assumed to be NUL-terminated.) In
395  * this case, g_socket_address_get_native_size() will always return
396  * the full size of a <literal>struct sockaddr_un</literal>, although
397  * g_unix_socket_address_get_path_len() will still return just the
398  * length of @path.
399  *
400  * %G_UNIX_SOCKET_ADDRESS_ABSTRACT is preferred over
401  * %G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED for new programs. Of course,
402  * when connecting to a server created by another process, you must
403  * use the appropriate type corresponding to how that process created
404  * its listening socket.
405  *
406  * Returns: a new #GUnixSocketAddress
407  *
408  * Since: 2.26
409  */
410 GSocketAddress *
411 g_unix_socket_address_new_with_type (const gchar            *path,
412                                      gint                    path_len,
413                                      GUnixSocketAddressType  type)
414 {
415   GSocketAddress *address;
416   GByteArray *array;
417
418   if (type == G_UNIX_SOCKET_ADDRESS_ANONYMOUS)
419     path_len = 0;
420   else if (path_len == -1)
421     path_len = strlen (path);
422
423   array = g_byte_array_sized_new (path_len);
424
425   g_byte_array_append (array, (guint8 *)path, path_len);
426
427   address = g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
428                           "path-as-array", array,
429                           "address-type", type,
430                           NULL);
431
432   g_byte_array_unref (array);
433
434   return address;
435 }
436
437 /**
438  * g_unix_socket_address_get_path:
439  * @address: a #GInetSocketAddress
440  *
441  * Gets @address's path, or for abstract sockets the "name".
442  *
443  * Guaranteed to be zero-terminated, but an abstract socket
444  * may contain embedded zeros, and thus you should use
445  * g_unix_socket_address_get_path_len() to get the true length
446  * of this string.
447  *
448  * Returns: the path for @address
449  *
450  * Since: 2.22
451  */
452 const char *
453 g_unix_socket_address_get_path (GUnixSocketAddress *address)
454 {
455   return address->priv->path;
456 }
457
458 /**
459  * g_unix_socket_address_get_path_len:
460  * @address: a #GInetSocketAddress
461  *
462  * Gets the length of @address's path.
463  *
464  * For details, see g_unix_socket_address_get_path().
465  *
466  * Returns: the length of the path
467  *
468  * Since: 2.22
469  */
470 gsize
471 g_unix_socket_address_get_path_len (GUnixSocketAddress *address)
472 {
473   return address->priv->path_len;
474 }
475
476 /**
477  * g_unix_socket_address_get_address_type:
478  * @address: a #GInetSocketAddress
479  *
480  * Gets @address's type.
481  *
482  * Returns: a #GUnixSocketAddressType
483  *
484  * Since: 2.26
485  */
486 GUnixSocketAddressType
487 g_unix_socket_address_get_address_type (GUnixSocketAddress *address)
488 {
489   return address->priv->address_type;
490 }
491
492 /**
493  * g_unix_socket_address_get_is_abstract:
494  * @address: a #GInetSocketAddress
495  *
496  * Tests if @address is abstract.
497  *
498  * Returns: %TRUE if the address is abstract, %FALSE otherwise
499  *
500  * Since: 2.22
501  *
502  * Deprecated: Use g_unix_socket_address_get_address_type()
503  */
504 gboolean
505 g_unix_socket_address_get_is_abstract (GUnixSocketAddress *address)
506 {
507   return (address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT ||
508           address->priv->address_type == G_UNIX_SOCKET_ADDRESS_ABSTRACT_PADDED);
509 }
510
511 /**
512  * g_unix_socket_address_abstract_names_supported:
513  *
514  * Checks if abstract unix domain socket names are supported.
515  *
516  * Returns: %TRUE if supported, %FALSE otherwise
517  *
518  * Since: 2.22
519  */
520 gboolean
521 g_unix_socket_address_abstract_names_supported (void)
522 {
523 #ifdef __linux__
524   return TRUE;
525 #else
526   return FALSE;
527 #endif
528 }
529
530 #define __G_UNIX_SOCKET_ADDRESS_C__
531 #include "gioaliasdef.c"