PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/gio/gunixsocketaddress.c

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