From: Marc-André Lureau Date: Tue, 8 Feb 2022 11:41:50 +0000 (+0400) Subject: dbus: add function for Unix sockets on Windows X-Git-Tag: dbus-1.15.0~26^2~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=655266f32e35c31c190ade3dbb3f93b3e9cafec3;p=thirdparty%2Fdbus.git dbus: add function for Unix sockets on Windows Signed-off-by: Marc-André Lureau --- diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index b74981c33..51445e8ca 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -48,6 +48,9 @@ #include #include #include +#ifdef HAVE_AFUNIX_H +#include +#endif /* Declarations missing in mingw's and windows sdk 7.0 headers */ extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR StringSid, PSID *Sid); @@ -4408,5 +4411,228 @@ _dbus_win_event_free (HANDLE handle, DBusError *error) return FALSE; } +#ifdef HAVE_AFUNIX_H +static dbus_bool_t +_dbus_open_socket (SOCKET *socket_p, + int domain, + int type, + int protocol, + DBusError *error) +{ + if (!_dbus_win_startup_winsock ()) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + *socket_p = socket (domain, type, protocol); + if (*socket_p == INVALID_SOCKET) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open socket: %s", + _dbus_strerror_from_errno ()); + return FALSE; + } + + _dbus_win_handle_set_close_on_exec ((HANDLE) *socket_p); + return TRUE; +} + +/** + * Opens a UNIX domain socket (as in the socket() call). + * Does not bind the socket. + * + * This will set CLOEXEC for the socket returned + * + * @param return location for socket descriptor + * @param error return location for an error + * @returns #FALSE if error is set + */ +static dbus_bool_t +_dbus_open_unix_socket (SOCKET *socket, + DBusError *error) +{ + return _dbus_open_socket (socket, AF_UNIX, SOCK_STREAM, 0, error); +} +#endif /* HAVE_AFUNIX_H */ + +/** + * Creates a socket and connects it to the UNIX domain socket at the + * given path. The socket is returned, and is set up as + * nonblocking. + * + * Abstract socket usage always fails. + * + * This will set FD_CLOEXEC for the socket returned. + * + * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace + * @param error return location for error code + * @returns a valid socket on success or an invalid socket on error + */ +DBusSocket +_dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + DBusSocket s = DBUS_SOCKET_INIT; + +#ifdef HAVE_AFUNIX_H + struct sockaddr_un addr; + size_t path_len; + + _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("connecting to unix socket %s abstract=%d\n", + path, abstract); + + if (abstract) + { + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to connect: UNIX abstract socket is not supported on this system"); + return s; + } + + path_len = strlen (path); + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Failed to connect: socket name too long"); + return s; + } + + if (!_dbus_open_unix_socket (&s.sock, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return s; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _DBUS_ZERO (addr); + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1); + + if (connect (s.sock, (struct sockaddr *) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to connect to socket %s: %s", + path, _dbus_strerror (errno)); + + _dbus_close_socket (&s, NULL); + return s; + } + + if (!_dbus_set_socket_nonblocking (s, error)) + _dbus_close_socket (&s, NULL); + +#else + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to connect: UNIX socket is not supported with this build"); +#endif + + return s; +} + +/** + * Creates a socket and binds it to the given path, + * then listens on the socket. The socket is + * set to be nonblocking. + * + * Abstract socket usage always fails. + * + * This will set CLOEXEC for the socket returned + * + * @param path the socket name + * @param abstract #TRUE to use abstract namespace + * @param error return location for errors + * @returns a valid socket on success or an invalid socket on error + */ +DBusSocket +_dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + DBusSocket s = DBUS_SOCKET_INIT; + +#ifdef HAVE_AFUNIX_H + struct sockaddr_un addr; + size_t path_len; + _DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("listening on unix socket %s abstract=%d\n", + path, abstract); + + if (abstract) + { + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to listen: UNIX abstract socket is not supported on this system"); + return s; + } + + if (!_dbus_open_unix_socket (&s.sock, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return s; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _DBUS_ZERO (addr); + addr.sun_family = AF_UNIX; + path_len = strlen (path); + + /* see related comment in dbus-sysdeps-unix.c */ + /* there is no S_ISSOCK on windows yet, so just unlink the path */ + unlink (path); + + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Failed to listen: socket name too long"); + _dbus_close_socket (&s, NULL); + return s; + } + + strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1); + + if (bind (s.sock, (struct sockaddr *) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to bind socket \"%s\": %s", + path, _dbus_strerror (errno)); + _dbus_close_socket (&s, NULL); + return s; + } + + if (listen (s.sock, SOMAXCONN /* backlog */) < 0) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to listen on socket \"%s\": %s", + path, _dbus_strerror (errno)); + _dbus_close_socket (&s, NULL); + return s; + } + + if (!_dbus_set_socket_nonblocking (s, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_close_socket (&s, NULL); + return s; + } +#else + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Failed to listen: UNIX socket is not supported with this build"); +#endif + + return s; +} + /** @} end of sysdeps-win */ /* tests in dbus-sysdeps-util.c */