Merge remote branch 'gvdb/master'
[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  *
38  * Support for UNIX-domain (aka local) sockets.
39  */
40
41 /**
42  * GUnixSocketAddress:
43  *
44  * A UNIX-domain (local) socket address, corresponding to a
45  * <type>struct sockaddr_un</type>.
46  */
47 G_DEFINE_TYPE (GUnixSocketAddress, g_unix_socket_address, G_TYPE_SOCKET_ADDRESS);
48
49 enum
50 {
51   PROP_0,
52   PROP_PATH,
53   PROP_PATH_AS_ARRAY,
54   PROP_ABSTRACT,
55 };
56
57 #define UNIX_PATH_MAX sizeof (((struct sockaddr_un *) 0)->sun_path)
58
59 struct _GUnixSocketAddressPrivate
60 {
61   char path[UNIX_PATH_MAX]; /* Not including the initial zero in abstract case, so
62                                we can guarantee zero termination of abstract
63                                pathnames in the get_path() API */
64   gsize path_len; /* Not including any terminating zeros */
65   gboolean abstract;
66 };
67
68 static void
69 g_unix_socket_address_set_property (GObject      *object,
70                                     guint         prop_id,
71                                     const GValue *value,
72                                     GParamSpec   *pspec)
73 {
74   GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
75   const char *str;
76   GByteArray *array;
77   gsize len;
78
79   switch (prop_id)
80     {
81     case PROP_PATH:
82       str = g_value_get_string (value);
83       if (str)
84         {
85           g_strlcpy (address->priv->path, str,
86                      sizeof (address->priv->path));
87           address->priv->path_len = strlen (address->priv->path);
88         }
89       break;
90
91     case PROP_PATH_AS_ARRAY:
92       array = g_value_get_boxed (value);
93
94       if (array)
95         {
96           /* Clip to fit in UNIX_PATH_MAX with zero termination or first byte */
97           len = MIN (array->len, UNIX_PATH_MAX-1);
98
99           /* Remove any trailing zeros from path_len */
100           while (len > 0 && array->data[len-1] == 0)
101             len--;
102
103           memcpy (address->priv->path, array->data, len);
104           address->priv->path[len] = 0; /* Ensure null-terminated */
105           address->priv->path_len = len;
106         }
107       break;
108
109     case PROP_ABSTRACT:
110       address->priv->abstract = g_value_get_boolean (value);
111       break;
112
113     default:
114       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
115     }
116 }
117
118 static void
119 g_unix_socket_address_get_property (GObject    *object,
120                                     guint       prop_id,
121                                     GValue     *value,
122                                     GParamSpec *pspec)
123 {
124   GUnixSocketAddress *address = G_UNIX_SOCKET_ADDRESS (object);
125   GByteArray *array;
126
127   switch (prop_id)
128     {
129       case PROP_PATH:
130         g_value_set_string (value, address->priv->path);
131         break;
132
133       case PROP_PATH_AS_ARRAY:
134         array = g_byte_array_sized_new (address->priv->path_len);
135         g_byte_array_append (array, (guint8 *)address->priv->path, address->priv->path_len);
136         g_value_take_boxed (value, array);
137         break;
138
139       case PROP_ABSTRACT:
140         g_value_set_boolean (value, address->priv->abstract);
141         break;
142
143       default:
144         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145     }
146 }
147
148 static GSocketFamily
149 g_unix_socket_address_get_family (GSocketAddress *address)
150 {
151   g_assert (PF_UNIX == G_SOCKET_FAMILY_UNIX);
152
153   return G_SOCKET_FAMILY_UNIX;
154 }
155
156 static gssize
157 g_unix_socket_address_get_native_size (GSocketAddress *address)
158 {
159   return sizeof (struct sockaddr_un);
160 }
161
162 static gboolean
163 g_unix_socket_address_to_native (GSocketAddress *address,
164                                  gpointer        dest,
165                                  gsize           destlen,
166                                  GError        **error)
167 {
168   GUnixSocketAddress *addr = G_UNIX_SOCKET_ADDRESS (address);
169   struct sockaddr_un *sock;
170
171   if (destlen < sizeof (*sock))
172     {
173       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
174                            _("Not enough space for socket address"));
175       return FALSE;
176     }
177
178   if (addr->priv->abstract &&
179       !g_unix_socket_address_abstract_names_supported ())
180     {
181       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
182                            _("Abstract unix domain socket addresses not supported on this system"));
183       return FALSE;
184     }
185
186   sock = (struct sockaddr_un *) dest;
187   sock->sun_family = AF_UNIX;
188   memset (sock->sun_path, 0, sizeof (sock->sun_path));
189   if (addr->priv->abstract)
190     {
191       sock->sun_path[0] = 0;
192       memcpy (sock->sun_path+1, addr->priv->path, addr->priv->path_len);
193     }
194   else
195     strcpy (sock->sun_path, addr->priv->path);
196
197   return TRUE;
198 }
199
200 static void
201 g_unix_socket_address_class_init (GUnixSocketAddressClass *klass)
202 {
203   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
204   GSocketAddressClass *gsocketaddress_class = G_SOCKET_ADDRESS_CLASS (klass);
205
206   g_type_class_add_private (klass, sizeof (GUnixSocketAddressPrivate));
207
208   gobject_class->set_property = g_unix_socket_address_set_property;
209   gobject_class->get_property = g_unix_socket_address_get_property;
210
211   gsocketaddress_class->get_family = g_unix_socket_address_get_family;
212   gsocketaddress_class->to_native = g_unix_socket_address_to_native;
213   gsocketaddress_class->get_native_size = g_unix_socket_address_get_native_size;
214
215   g_object_class_install_property (gobject_class,
216                                    PROP_PATH,
217                                    g_param_spec_string ("path",
218                                                         P_("Path"),
219                                                         P_("UNIX socket path"),
220                                                         NULL,
221                                                         G_PARAM_READWRITE |
222                                                         G_PARAM_CONSTRUCT_ONLY |
223                                                         G_PARAM_STATIC_STRINGS));
224   g_object_class_install_property (gobject_class, PROP_PATH_AS_ARRAY,
225                                    g_param_spec_boxed ("path-as-array",
226                                                        P_("Path array"),
227                                                        P_("UNIX socket path, as byte array"),
228                                                        G_TYPE_BYTE_ARRAY,
229                                                        G_PARAM_READWRITE |
230                                                        G_PARAM_CONSTRUCT_ONLY |
231                                                        G_PARAM_STATIC_STRINGS));
232   g_object_class_install_property (gobject_class, PROP_ABSTRACT,
233                                    g_param_spec_boolean ("abstract",
234                                                          P_("Abstract"),
235                                                          P_("Whether or not this is an abstract address"),
236                                                          FALSE,
237                                                          G_PARAM_READWRITE |
238                                                          G_PARAM_CONSTRUCT_ONLY |
239                                                          G_PARAM_STATIC_STRINGS));
240 }
241
242 static void
243 g_unix_socket_address_init (GUnixSocketAddress *address)
244 {
245   address->priv = G_TYPE_INSTANCE_GET_PRIVATE (address,
246                                                G_TYPE_UNIX_SOCKET_ADDRESS,
247                                                GUnixSocketAddressPrivate);
248
249   memset (address->priv->path, 0, sizeof (address->priv->path));
250   address->priv->path_len = -1;
251 }
252
253 /**
254  * g_unix_socket_address_new:
255  * @path: the socket path
256  *
257  * Creates a new #GUnixSocketAddress for @path.
258  *
259  * To create abstract socket addresses, on systems that support that,
260  * use g_unix_socket_address_new_abstract().
261  *
262  * Returns: a new #GUnixSocketAddress
263  *
264  * Since: 2.22
265  */
266 GSocketAddress *
267 g_unix_socket_address_new (const gchar *path)
268 {
269   return g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
270                        "path", path,
271                        "abstract", FALSE,
272                        NULL);
273 }
274
275 /**
276  * g_unix_socket_address_new_abstract:
277  * @path: the abstract name
278  * @path_len: the length of @path, or -1
279  *
280  * Creates a new abstract #GUnixSocketAddress for @path.
281  *
282  * Unix domain sockets are generally visible in the filesystem. However, some
283  * systems support abstract socket name which are not visible in the
284  * filesystem and not affected by the filesystem permissions, visibility, etc.
285  *
286  * Note that not all systems (really only Linux) support abstract
287  * socket names, so if you use them on other systems function calls may
288  * return %G_IO_ERROR_NOT_SUPPORTED errors. You can use
289  * g_unix_socket_address_abstract_names_supported() to see if abstract
290  * names are supported.
291  *
292  * If @path_len is -1 then @path is assumed to be a zero terminated
293  * string (although in general abstract names need not be zero terminated
294  * and can have embedded nuls). All bytes after @path_len up to the max size
295  * of an abstract unix domain name is filled with zero bytes.
296  *
297  * Returns: a new #GUnixSocketAddress
298  *
299  * Since: 2.22
300  */
301 GSocketAddress *
302 g_unix_socket_address_new_abstract (const gchar *path,
303                                     int path_len)
304 {
305   GSocketAddress *address;
306   GByteArray *array;
307
308   if (path_len == -1)
309     path_len = strlen (path);
310
311   array = g_byte_array_sized_new (path_len);
312
313   g_byte_array_append (array, (guint8 *)path, path_len);
314
315   address = g_object_new (G_TYPE_UNIX_SOCKET_ADDRESS,
316                           "path-as-array", array,
317                           "abstract", TRUE,
318                           NULL);
319
320   g_byte_array_unref (array);
321
322   return address;
323 }
324
325 /**
326  * g_unix_socket_address_get_path:
327  * @address: a #GInetSocketAddress
328  *
329  * Gets @address's path, or for abstract sockets the "name".
330  *
331  * Guaranteed to be zero-terminated, but an abstract socket
332  * may contain embedded zeros, and thus you should use
333  * g_unix_socket_address_get_path_len() to get the true length
334  * of this string.
335  *
336  * Returns: the path for @address
337  *
338  * Since: 2.22
339  */
340 const char *
341 g_unix_socket_address_get_path (GUnixSocketAddress *address)
342 {
343   return address->priv->path;
344 }
345
346 /**
347  * g_unix_socket_address_get_path_len:
348  * @address: a #GInetSocketAddress
349  *
350  * Gets the length of @address's path.
351  *
352  * For details, see g_unix_socket_address_get_path().
353  *
354  * Returns: the length of the path
355  *
356  * Since: 2.22
357  */
358 gsize
359 g_unix_socket_address_get_path_len (GUnixSocketAddress *address)
360 {
361   return address->priv->path_len;
362 }
363
364 /**
365  * g_unix_socket_address_get_is_abstract:
366  * @address: a #GInetSocketAddress
367  *
368  * Gets @address's path.
369  *
370  * Returns: %TRUE if the address is abstract, %FALSE otherwise
371  *
372  * Since: 2.22
373  */
374 gboolean
375 g_unix_socket_address_get_is_abstract (GUnixSocketAddress *address)
376 {
377   return address->priv->abstract;
378 }
379
380 /**
381  * g_unix_socket_address_abstract_names_supported:
382  *
383  * Checks if abstract unix domain socket names are supported.
384  *
385  * Returns: %TRUE if supported, %FALSE otherwise
386  *
387  * Since: 2.22
388  */
389 gboolean
390 g_unix_socket_address_abstract_names_supported (void)
391 {
392 #ifdef __linux__
393   return TRUE;
394 #else
395   return FALSE;
396 #endif
397 }
398
399 #define __G_UNIX_SOCKET_ADDRESS_C__
400 #include "gioaliasdef.c"