Merge branch 'win32-uds' into 'master'

Add Unix socket support on Windows

See merge request dbus/dbus!249
This commit is contained in:
Simon McVittie 2022-07-15 16:14:55 +00:00
commit b3163746a9
36 changed files with 1047 additions and 617 deletions

View file

@ -5181,9 +5181,9 @@ bus_unix_fds_passing_test (const char *test_data_dir_cstr)
DBUS_TYPE_INVALID))
_dbus_test_fatal ("Failed to attach fds.");
if (!_dbus_close_socket (one[0], &error))
if (!_dbus_close_socket (&one[0], &error))
_dbus_test_fatal ("Failed to close pipe #1 ");
if (!_dbus_close_socket (two[0], &error))
if (!_dbus_close_socket (&two[0], &error))
_dbus_test_fatal ("Failed to close pipe #2 ");
if (!(dbus_connection_can_send_type(foo, DBUS_TYPE_UNIX_FD)))
@ -5250,9 +5250,9 @@ bus_unix_fds_passing_test (const char *test_data_dir_cstr)
if (read(two[1].fd, &r, 1) != 1 || r != 'Z')
_dbus_test_fatal ("Failed to read value from pipe.");
if (!_dbus_close_socket (one[1], &error))
if (!_dbus_close_socket (&one[1], &error))
_dbus_test_fatal ("Failed to close pipe #1 ");
if (!_dbus_close_socket (two[1], &error))
if (!_dbus_close_socket (&two[1], &error))
_dbus_test_fatal ("Failed to close pipe #2 ");
_dbus_verbose ("Disconnecting foo\n");

View file

@ -387,11 +387,8 @@ close_reload_pipe (DBusWatch **watch)
_dbus_watch_unref (*watch);
*watch = NULL;
_dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL);
_dbus_socket_invalidate (&reload_pipe[RELOAD_READ_END]);
_dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL);
_dbus_socket_invalidate (&reload_pipe[RELOAD_WRITE_END]);
_dbus_close_socket (&reload_pipe[RELOAD_READ_END], NULL);
_dbus_close_socket (&reload_pipe[RELOAD_WRITE_END], NULL);
}
#endif /* DBUS_UNIX */

View file

@ -6,6 +6,7 @@ include(CheckTypeSize)
include(CheckCSourceCompiles)
include(CheckCSourceRuns)
check_include_files("winsock2.h;afunix.h" HAVE_AFUNIX_H)
check_include_file(alloca.h HAVE_ALLOCA_H)
check_include_file(byteswap.h HAVE_BYTESWAP_H)
check_include_file(crt/externs.h HAVE_CRT_EXTERNS_H)

View file

@ -94,6 +94,7 @@
#cmakedefine GLIB_VERSION_MAX_ALLOWED @GLIB_VERSION_MAX_ALLOWED@
// headers
#cmakedefine HAVE_AFUNIX_H 1
#cmakedefine HAVE_ALLOCA_H 1
#cmakedefine HAVE_BYTESWAP_H 1
#cmakedefine HAVE_CRT_EXTERNS_H 1

View file

@ -430,6 +430,7 @@ sys/syscall.h
sys/syslimits.h
sys/time.h
unistd.h
winsock2.h
ws2tcpip.h
])
@ -1052,6 +1053,13 @@ if test x$dbus_win = xyes ; then
fi
fi
AC_CHECK_HEADERS([afunix.h], [], [],
[AC_INCLUDES_DEFAULT[
#ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
#endif
]])
AC_SUBST([NETWORK_libs])
AC_ARG_WITH([valgrind],

View file

@ -89,7 +89,6 @@ set(DBUS_LIB_HEADERS
dbus-resources.h
dbus-server-debug-pipe.h
dbus-server-protected.h
dbus-server-unix.h
dbus-sha.h
dbus-timeout.h
dbus-threads.h
@ -209,7 +208,6 @@ else(WIN32)
dbus-userdb.c
)
set(DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS}
dbus-server-unix.h
dbus-transport-unix.h
dbus-sysdeps-unix.h
dbus-userdb.h

View file

@ -102,8 +102,7 @@ endif
DBUS_LIB_arch_sources = \
dbus-uuidgen.c \
dbus-uuidgen.h \
dbus-server-unix.c \
dbus-server-unix.h
dbus-server-unix.c
DBUS_SHARED_arch_sources = \
$(launchd_source) \

View file

@ -334,18 +334,7 @@ _dbus_verbose_init (void)
}
}
/** @def DBUS_IS_DIR_SEPARATOR(c)
* macro for checking if character c is a patch separator
*
* @todo move to a header file so that others can use this too
*/
#ifdef DBUS_WIN
#define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
#else
#define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
#endif
/**
/**
remove source root from file path
the source root is determined by
*/

View file

@ -488,6 +488,19 @@ dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str,
# define _DBUS_END_IGNORE_LEAKS do { } while (0)
#endif
/** @def DBUS_IS_DIR_SEPARATOR(c)
* macro for checking if character c is a path separator
*/
#ifdef DBUS_WIN
#define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
#define DBUS_DIR_SEPARATOR '\\'
#define DBUS_DIR_SEPARATOR_S "\\"
#else
#define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
#define DBUS_DIR_SEPARATOR '/'
#define DBUS_DIR_SEPARATOR_S "/"
#endif
DBUS_END_DECLS
#endif /* DBUS_INTERNALS_H */

View file

@ -194,8 +194,7 @@ _dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefil
if (do_check_nonce(fd, &nonce, NULL) != TRUE) {
_dbus_verbose ("nonce check failed. Closing socket.\n");
_dbus_close_socket(fd, NULL);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
goto out;
}

View file

@ -260,8 +260,8 @@ _dbus_transport_debug_pipe_new (const char *server_name,
NULL, &address);
if (client_transport == NULL)
{
_dbus_close_socket (client_fd, NULL);
_dbus_close_socket (server_fd, NULL);
_dbus_close_socket (&client_fd, NULL);
_dbus_close_socket (&server_fd, NULL);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_string_free (&address);
return NULL;
@ -276,7 +276,7 @@ _dbus_transport_debug_pipe_new (const char *server_name,
if (server_transport == NULL)
{
_dbus_transport_unref (client_transport);
_dbus_close_socket (server_fd, NULL);
_dbus_close_socket (&server_fd, NULL);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}

View file

@ -126,6 +126,10 @@ typedef enum
DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED /**< address is already used */
} DBusServerListenResult;
DBusServerListenResult _dbus_server_listen_unix_socket (DBusAddressEntry *entry,
DBusServer **server_p,
DBusError *error);
DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
DBusServer **server_p,
DBusError *error);

View file

@ -103,7 +103,7 @@ handle_new_client_fd_and_unlock (DBusServer *server,
transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL);
if (transport == NULL)
{
_dbus_close_socket (client_fd, NULL);
_dbus_close_socket (&client_fd, NULL);
SERVER_UNLOCK (server);
return FALSE;
}
@ -242,10 +242,7 @@ socket_disconnect (DBusServer *server)
}
if (_dbus_socket_is_valid (socket_server->fds[i]))
{
_dbus_close_socket (socket_server->fds[i], NULL);
_dbus_socket_invalidate (&socket_server->fds[i]);
}
_dbus_close_socket (&socket_server->fds[i], NULL);
}
if (socket_server->socket_name != NULL)
@ -513,7 +510,7 @@ failed:
if (listen_fds != NULL)
{
for (i = 0; i < nlisten_fds; i++)
_dbus_close_socket (listen_fds[i], NULL);
_dbus_close_socket (&listen_fds[i], NULL);
dbus_free (listen_fds);
}
@ -596,5 +593,298 @@ _dbus_server_socket_own_filename (DBusServer *server,
socket_server->socket_name = filename;
}
/**
* Creates a new server listening on the given Unix domain socket.
*
* @param path the path for the domain socket.
* @param abstract #TRUE to use abstract socket namespace
* @param error location to store reason for failure.
* @returns the new server, or #NULL on failure.
*/
DBusServer*
_dbus_server_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
DBusServer *server;
DBusSocket listen_fd;
DBusString address;
char *path_copy;
DBusString path_str;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!_dbus_string_init (&address))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
_dbus_string_init_const (&path_str, path);
if ((abstract &&
!_dbus_string_append (&address, "unix:abstract=")) ||
(!abstract &&
!_dbus_string_append (&address, "unix:path=")) ||
!_dbus_address_append_escaped (&address, &path_str))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
if (abstract)
{
path_copy = NULL;
}
else
{
path_copy = _dbus_strdup (path);
if (path_copy == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
}
listen_fd = _dbus_listen_unix_socket (path, abstract, error);
if (!_dbus_socket_is_valid (listen_fd))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed_1;
}
server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
if (server == NULL)
{
goto failed_2;
}
if (path_copy != NULL)
_dbus_server_socket_own_filename(server, path_copy);
_dbus_string_free (&address);
return server;
failed_2:
_dbus_close_socket (&listen_fd, NULL);
failed_1:
dbus_free (path_copy);
failed_0:
_dbus_string_free (&address);
return NULL;
}
/**
* Creates a new Unix domain socket server listening under the given directory.
* This function is used for "unix:dir/tmpdir" kind of addresses.
*
* @param dir the path to a directory.
* @param abstract #TRUE to use abstract socket namespace
* @param error location to store reason for failure.
* @returns the new server, or #NULL on failure.
*/
DBusServer *
_dbus_server_new_for_dir (const char *dir,
dbus_bool_t use_abstract,
DBusError *error)
{
DBusServer *server;
DBusString full_path;
DBusString filename;
if (!_dbus_string_init (&full_path))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if (!_dbus_string_init (&filename))
{
_dbus_string_free (&full_path);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if (!_dbus_string_append (&filename, "dbus-"))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if (!_dbus_generate_random_ascii (&filename, 10, error))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
return NULL;
}
if (!_dbus_string_append (&full_path, dir) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
server =
_dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
use_abstract,
error);
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
return server;
}
/**
* Tries to interpret the address entry for UNIX socket
* addresses.
*
* Sets error if the result is not OK.
*
* @param entry an address entry
* @param server_p location to store a new DBusServer, or #NULL on failure.
* @param error location to store rationale for failure on bad address
* @returns the outcome
*
*/
DBusServerListenResult
_dbus_server_listen_unix_socket (DBusAddressEntry *entry,
DBusServer **server_p,
DBusError *error)
{
const char *method;
*server_p = NULL;
method = dbus_address_entry_get_method (entry);
if (strcmp (method, "unix") == 0)
{
const char *path = dbus_address_entry_get_value (entry, "path");
const char *dir = dbus_address_entry_get_value (entry, "dir");
const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
const char *abstract = dbus_address_entry_get_value (entry, "abstract");
const char *runtime = dbus_address_entry_get_value (entry, "runtime");
int mutually_exclusive_modes = 0;
mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
(abstract != NULL) + (runtime != NULL) + (dir != NULL);
if (mutually_exclusive_modes < 1)
{
_dbus_set_bad_address(error, "unix",
"path or tmpdir or abstract or runtime or dir",
NULL);
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
if (mutually_exclusive_modes > 1)
{
_dbus_set_bad_address(error, NULL, NULL,
"cannot specify two of \"path\", \"tmpdir\", \"abstract\", \"runtime\" and \"dir\" at the same time");
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
if (runtime != NULL)
{
DBusString full_path;
DBusString filename;
const char *runtimedir;
if (strcmp (runtime, "yes") != 0)
{
_dbus_set_bad_address(error, NULL, NULL,
"if given, the only value allowed for \"runtime\" is \"yes\"");
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
if (runtimedir == NULL)
{
dbus_set_error (error,
DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
_dbus_string_init_const (&filename, "bus");
if (!_dbus_string_init (&full_path))
{
_DBUS_SET_OOM (error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
if (!_dbus_string_append (&full_path, runtimedir) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
_dbus_string_free (&full_path);
_DBUS_SET_OOM (error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
/* We can safely use filesystem sockets in the runtime directory,
* and they are preferred because they can be bind-mounted between
* Linux containers. */
*server_p = _dbus_server_new_for_domain_socket (
_dbus_string_get_const_data (&full_path),
FALSE, error);
_dbus_string_free (&full_path);
}
else if (tmpdir != NULL || dir != NULL)
{
dbus_bool_t use_abstract = FALSE;
if (tmpdir != NULL)
{
dir = tmpdir;
#ifdef __linux__
/* Use abstract sockets for tmpdir if supported, so that it
* never needs to be cleaned up. Use dir instead if you want a
* path-based socket. */
use_abstract = TRUE;
#endif
}
*server_p = _dbus_server_new_for_dir (dir, use_abstract, error);
}
else
{
if (path)
*server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
else
*server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
}
if (*server_p != NULL)
{
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
return DBUS_SERVER_LISTEN_OK;
}
else
{
_DBUS_ASSERT_ERROR_IS_SET(error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
}
else
{
/* If we don't handle the method, we return NULL with the
* error unset
*/
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
return DBUS_SERVER_LISTEN_NOT_HANDLED;
}
}
/** @} */

View file

@ -43,6 +43,9 @@ DBusServer* _dbus_server_new_for_tcp_socket (const char *host,
const char *family,
DBusError *error,
dbus_bool_t use_nonce);
DBusServer* _dbus_server_new_for_dir (const char *dir,
dbus_bool_t use_abstract,
DBusError *error);
DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry,
DBusServer **server_p,
DBusError *error);
@ -51,6 +54,9 @@ DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry,
void _dbus_server_socket_own_filename (DBusServer *server,
char *filename);
DBusServer* _dbus_server_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
DBUS_END_DECLS
#endif /* DBUS_SERVER_SOCKET_H */

View file

@ -23,7 +23,6 @@
#include <config.h>
#include "dbus-internals.h"
#include "dbus-server-unix.h"
#include "dbus-server-socket.h"
#include "dbus-server-launchd.h"
#include "dbus-transport-unix.h"
@ -60,164 +59,7 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
*server_p = NULL;
method = dbus_address_entry_get_method (entry);
if (strcmp (method, "unix") == 0)
{
const char *path = dbus_address_entry_get_value (entry, "path");
const char *dir = dbus_address_entry_get_value (entry, "dir");
const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
const char *abstract = dbus_address_entry_get_value (entry, "abstract");
const char *runtime = dbus_address_entry_get_value (entry, "runtime");
int mutually_exclusive_modes = 0;
mutually_exclusive_modes = (path != NULL) + (tmpdir != NULL) +
(abstract != NULL) + (runtime != NULL) + (dir != NULL);
if (mutually_exclusive_modes < 1)
{
_dbus_set_bad_address(error, "unix",
"path or tmpdir or abstract or runtime or dir",
NULL);
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
if (mutually_exclusive_modes > 1)
{
_dbus_set_bad_address(error, NULL, NULL,
"cannot specify two of \"path\", \"tmpdir\", \"abstract\", \"runtime\" and \"dir\" at the same time");
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
if (runtime != NULL)
{
DBusString full_path;
DBusString filename;
const char *runtimedir;
if (strcmp (runtime, "yes") != 0)
{
_dbus_set_bad_address(error, NULL, NULL,
"if given, the only value allowed for \"runtime\" is \"yes\"");
return DBUS_SERVER_LISTEN_BAD_ADDRESS;
}
runtimedir = _dbus_getenv ("XDG_RUNTIME_DIR");
if (runtimedir == NULL)
{
dbus_set_error (error,
DBUS_ERROR_NOT_SUPPORTED, "\"XDG_RUNTIME_DIR\" is not set");
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
_dbus_string_init_const (&filename, "bus");
if (!_dbus_string_init (&full_path))
{
_DBUS_SET_OOM (error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
if (!_dbus_string_append (&full_path, runtimedir) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
_dbus_string_free (&full_path);
_DBUS_SET_OOM (error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
/* We can safely use filesystem sockets in the runtime directory,
* and they are preferred because they can be bind-mounted between
* Linux containers. */
*server_p = _dbus_server_new_for_domain_socket (
_dbus_string_get_const_data (&full_path),
FALSE, error);
_dbus_string_free (&full_path);
}
else if (tmpdir != NULL || dir != NULL)
{
DBusString full_path;
DBusString filename;
dbus_bool_t use_abstract = FALSE;
if (tmpdir != NULL)
{
dir = tmpdir;
#ifdef __linux__
/* Use abstract sockets for tmpdir if supported, so that it
* never needs to be cleaned up. Use dir instead if you want a
* path-based socket. */
use_abstract = TRUE;
#endif
}
if (!_dbus_string_init (&full_path))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
if (!_dbus_string_init (&filename))
{
_dbus_string_free (&full_path);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
if (!_dbus_string_append (&filename, "dbus-"))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
if (!_dbus_generate_random_ascii (&filename, 10, error))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
if (!_dbus_string_append (&full_path, dir) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
*server_p =
_dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
use_abstract,
error);
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
}
else
{
if (path)
*server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
else
*server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
}
if (*server_p != NULL)
{
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
return DBUS_SERVER_LISTEN_OK;
}
else
{
_DBUS_ASSERT_ERROR_IS_SET(error);
return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
}
}
else if (strcmp (method, "systemd") == 0)
if (strcmp (method, "systemd") == 0)
{
int i, n;
DBusSocket *fds;
@ -258,7 +100,7 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
systemd_err:
for (i = 0; i < n; i++)
{
_dbus_close_socket (fds[i], NULL);
_dbus_close_socket (&fds[i], NULL);
}
dbus_free (fds);
_dbus_string_free (&address);
@ -298,87 +140,4 @@ _dbus_server_listen_platform_specific (DBusAddressEntry *entry,
}
}
/**
* Creates a new server listening on the given Unix domain socket.
*
* @param path the path for the domain socket.
* @param abstract #TRUE to use abstract socket namespace
* @param error location to store reason for failure.
* @returns the new server, or #NULL on failure.
*/
DBusServer*
_dbus_server_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
DBusServer *server;
DBusSocket listen_fd;
DBusString address;
char *path_copy;
DBusString path_str;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!_dbus_string_init (&address))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
_dbus_string_init_const (&path_str, path);
if ((abstract &&
!_dbus_string_append (&address, "unix:abstract=")) ||
(!abstract &&
!_dbus_string_append (&address, "unix:path=")) ||
!_dbus_address_append_escaped (&address, &path_str))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
if (abstract)
{
path_copy = NULL;
}
else
{
path_copy = _dbus_strdup (path);
if (path_copy == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
}
listen_fd.fd = _dbus_listen_unix_socket (path, abstract, error);
if (listen_fd.fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed_1;
}
server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0, error);
if (server == NULL)
{
goto failed_2;
}
if (path_copy != NULL)
_dbus_server_socket_own_filename(server, path_copy);
_dbus_string_free (&address);
return server;
failed_2:
_dbus_close_socket (listen_fd, NULL);
failed_1:
dbus_free (path_copy);
failed_0:
_dbus_string_free (&address);
return NULL;
}
/** @} */

View file

@ -1,37 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* dbus-server-unix.h Server implementation for Unix network protocols.
*
* Copyright (C) 2002 Red Hat Inc.
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef DBUS_SERVER_UNIX_H
#define DBUS_SERVER_UNIX_H
#include <dbus/dbus-internals.h>
#include <dbus/dbus-server-protected.h>
DBUS_BEGIN_DECLS
DBusServer* _dbus_server_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
DBUS_END_DECLS
#endif /* DBUS_SERVER_UNIX_H */

View file

@ -23,7 +23,6 @@
#include <config.h>
#include "dbus-server.h"
#include "dbus-server-unix.h"
#include "dbus-server-socket.h"
#include "dbus-string.h"
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
@ -527,6 +526,7 @@ static const struct {
DBusError *error);
} listen_funcs[] = {
{ _dbus_server_listen_socket }
, { _dbus_server_listen_unix_socket }
, { _dbus_server_listen_platform_specific }
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
, { _dbus_server_listen_debug_pipe }

View file

@ -560,7 +560,7 @@ close_socket_to_babysitter (DBusBabysitter *sitter)
if (sitter->socket_to_babysitter.fd >= 0)
{
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
_dbus_close_socket (&sitter->socket_to_babysitter, NULL);
sitter->socket_to_babysitter.fd = -1;
}
}

View file

@ -160,7 +160,7 @@ close_socket_to_babysitter (DBusBabysitter *sitter)
if (sitter->socket_to_babysitter.sock != INVALID_SOCKET)
{
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
_dbus_close_socket (&sitter->socket_to_babysitter, NULL);
sitter->socket_to_babysitter.sock = INVALID_SOCKET;
}
}
@ -188,7 +188,7 @@ _dbus_babysitter_unref (DBusBabysitter *sitter)
if (sitter->socket_to_main.sock != INVALID_SOCKET)
{
_dbus_close_socket (sitter->socket_to_main, NULL);
_dbus_close_socket (&sitter->socket_to_main, NULL);
sitter->socket_to_main.sock = INVALID_SOCKET;
}

View file

@ -293,22 +293,34 @@ static dbus_bool_t
_dbus_open_unix_socket (int *fd,
DBusError *error)
{
return _dbus_open_socket(fd, PF_UNIX, SOCK_STREAM, 0, error);
return _dbus_open_socket(fd, AF_UNIX, SOCK_STREAM, 0, error);
}
/**
* Closes a socket. Should not be used on non-socket
* file descriptors or handles.
* Closes a socket and invalidates it. Should not be used on non-socket file
* descriptors or handles.
*
* If an error is detected, this function returns #FALSE and sets the error, but
* the socket is still closed and invalidated. Callers can use the error in a
* diagnostic message, but should not retry closing the socket.
*
* @param fd the socket
* @param error return location for an error
* @returns #FALSE if error is set
*/
dbus_bool_t
_dbus_close_socket (DBusSocket fd,
_dbus_close_socket (DBusSocket *fd,
DBusError *error)
{
return _dbus_close (fd.fd, error);
dbus_bool_t rv;
_dbus_assert (fd != NULL);
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
rv = _dbus_close (fd->fd, error);
_dbus_socket_invalidate (fd);
return rv;
}
/**
@ -923,21 +935,6 @@ _dbus_write_two (int fd,
#endif /* !HAVE_WRITEV */
}
#define _DBUS_MAX_SUN_PATH_LENGTH 99
/**
* @def _DBUS_MAX_SUN_PATH_LENGTH
*
* Maximum length of the path to a UNIX domain socket,
* sockaddr_un::sun_path member. POSIX requires that all systems
* support at least 100 bytes here, including the nul termination.
* We use 99 for the max value to allow for the nul.
*
* We could probably also do sizeof (addr.sun_path)
* but this way we are the same on all platforms
* which is probably a good idea.
*/
/**
* Creates a socket and connects it to the UNIX domain socket at the
* given path. The connection fd is returned, and is set up as
@ -952,14 +949,14 @@ _dbus_write_two (int fd,
* @param path the path to UNIX domain socket
* @param abstract #TRUE to use abstract namespace
* @param error return location for error code
* @returns connection file descriptor or -1 on error
* @returns a valid socket on success or an invalid socket on error
*/
int
DBusSocket
_dbus_connect_unix_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
int fd;
DBusSocket fd = DBUS_SOCKET_INIT;
size_t path_len;
struct sockaddr_un addr;
_DBUS_STATIC_ASSERT (sizeof (addr.sun_path) > _DBUS_MAX_SUN_PATH_LENGTH);
@ -970,10 +967,10 @@ _dbus_connect_unix_socket (const char *path,
path, abstract);
if (!_dbus_open_unix_socket (&fd, error))
if (!_dbus_open_unix_socket (&fd.fd, error))
{
_DBUS_ASSERT_ERROR_IS_SET(error);
return -1;
return fd;
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
@ -991,8 +988,8 @@ _dbus_connect_unix_socket (const char *path,
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Abstract socket name too long\n");
_dbus_close (fd, NULL);
return -1;
_dbus_close_socket (&fd, NULL);
return fd;
}
strncpy (&addr.sun_path[1], path, sizeof (addr.sun_path) - 2);
@ -1000,8 +997,8 @@ _dbus_connect_unix_socket (const char *path,
#else /* !__linux__ */
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
"Operating system does not support abstract socket namespace\n");
_dbus_close (fd, NULL);
return -1;
_dbus_close_socket (&fd, NULL);
return fd;
#endif /* !__linux__ */
}
else
@ -1010,30 +1007,30 @@ _dbus_connect_unix_socket (const char *path,
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Socket name too long\n");
_dbus_close (fd, NULL);
return -1;
_dbus_close_socket (&fd, NULL);
return fd;
}
strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1);
}
if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
if (connect (fd.fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
{
dbus_set_error (error,
_dbus_error_from_errno (errno),
"Failed to connect to socket %s: %s",
path, _dbus_strerror (errno));
_dbus_close (fd, NULL);
return -1;
_dbus_close_socket (&fd, NULL);
return fd;
}
if (!_dbus_set_fd_nonblocking (fd, error))
if (!_dbus_set_fd_nonblocking (fd.fd, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_close (fd, NULL);
return -1;
_dbus_close_socket (&fd, NULL);
return fd;
}
return fd;
@ -1049,13 +1046,14 @@ _dbus_connect_unix_socket (const char *path,
* @param argv the argument list for the process to execute.
* argv[0] typically is identical to the path of the executable
* @param error return location for error code
* @returns connection file descriptor or -1 on error
* @returns a valid socket on success or an invalid socket on error
*/
int
DBusSocket
_dbus_connect_exec (const char *path,
char *const argv[],
DBusError *error)
{
DBusSocket s = DBUS_SOCKET_INIT;
int fds[2];
pid_t pid;
int retval;
@ -1081,7 +1079,8 @@ _dbus_connect_exec (const char *path,
_dbus_error_from_errno (errno),
"Failed to create socket pair: %s",
_dbus_strerror (errno));
return -1;
_dbus_assert (!_dbus_socket_is_valid (s));
return s;
}
if (!cloexec_done)
@ -1104,7 +1103,8 @@ _dbus_connect_exec (const char *path,
path, _dbus_strerror (errno));
close (fds[0]);
close (fds[1]);
return -1;
_dbus_assert (!_dbus_socket_is_valid (s));
return s;
}
if (pid == 0)
@ -1139,10 +1139,12 @@ _dbus_connect_exec (const char *path,
_DBUS_ASSERT_ERROR_IS_SET (error);
close (fds[0]);
return -1;
_dbus_assert (!_dbus_socket_is_valid (s));
return s;
}
return fds[0];
s.fd = fds[0];
return s;
}
/**
@ -1160,13 +1162,14 @@ _dbus_connect_exec (const char *path,
* @param path the socket name
* @param abstract #TRUE to use abstract namespace
* @param error return location for errors
* @returns the listening file descriptor or -1 on error
* @returns a valid socket on success or an invalid socket on error
*/
int
DBusSocket
_dbus_listen_unix_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
DBusSocket s = DBUS_SOCKET_INIT;
int listen_fd;
struct sockaddr_un addr;
size_t path_len;
@ -1180,7 +1183,7 @@ _dbus_listen_unix_socket (const char *path,
if (!_dbus_open_unix_socket (&listen_fd, error))
{
_DBUS_ASSERT_ERROR_IS_SET(error);
return -1;
return s;
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
@ -1202,7 +1205,7 @@ _dbus_listen_unix_socket (const char *path,
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Abstract socket name too long\n");
_dbus_close (listen_fd, NULL);
return -1;
return s;
}
strncpy (&addr.sun_path[1], path, sizeof (addr.sun_path) - 2);
@ -1211,7 +1214,7 @@ _dbus_listen_unix_socket (const char *path,
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
"Operating system does not support abstract socket namespace\n");
_dbus_close (listen_fd, NULL);
return -1;
return s;
#endif /* !__linux__ */
}
else
@ -1239,8 +1242,8 @@ _dbus_listen_unix_socket (const char *path,
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
"Socket name too long\n");
_dbus_close (listen_fd, NULL);
return -1;
}
return s;
}
strncpy (addr.sun_path, path, sizeof (addr.sun_path) - 1);
}
@ -1251,7 +1254,7 @@ _dbus_listen_unix_socket (const char *path,
"Failed to bind socket \"%s\": %s",
path, _dbus_strerror (errno));
_dbus_close (listen_fd, NULL);
return -1;
return s;
}
if (listen (listen_fd, SOMAXCONN /* backlog */) < 0)
@ -1260,14 +1263,14 @@ _dbus_listen_unix_socket (const char *path,
"Failed to listen on socket \"%s\": %s",
path, _dbus_strerror (errno));
_dbus_close (listen_fd, NULL);
return -1;
return s;
}
if (!_dbus_set_fd_nonblocking (listen_fd, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_close (listen_fd, NULL);
return -1;
return s;
}
/* Try opening up the permissions, but if we can't, just go ahead
@ -1276,7 +1279,8 @@ _dbus_listen_unix_socket (const char *path,
if (!abstract && chmod (path, 0777) < 0)
_dbus_warn ("Could not set mode 0777 on socket %s", path);
return listen_fd;
s.fd = listen_fd;
return s;
}
/**
@ -1491,7 +1495,6 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
_dbus_error_from_gai (res, errno),
"Failed to lookup host/port: \"%s:%s\": %s (%d)",
host, port, gai_strerror(res), res);
_dbus_socket_invalidate (&fd);
goto out;
}
@ -1509,8 +1512,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (connect (fd.fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
{
saved_errno = errno;
_dbus_close (fd.fd, NULL);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
connect_error = dbus_new0 (DBusError, 1);
@ -1557,16 +1559,14 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (!ret)
{
_dbus_close (fd.fd, NULL);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
goto out;
}
}
if (!_dbus_set_fd_nonblocking (fd.fd, error))
{
_dbus_close (fd.fd, NULL);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
goto out;
}

View file

@ -66,17 +66,6 @@ _dbus_write_two (int fd,
int start2,
int len2);
int _dbus_connect_unix_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
int _dbus_listen_unix_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
int _dbus_connect_exec (const char *path,
char *const argv[],
DBusError *error);
int _dbus_listen_systemd_sockets (DBusSocket **fd,
DBusError *error);

View file

@ -48,6 +48,9 @@
#include <windows.h>
#include <wincrypt.h>
#include <iphlpapi.h>
#ifdef HAVE_AFUNIX_H
#include <afunix.h>
#endif
/* Declarations missing in mingw's and windows sdk 7.0 headers */
extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR StringSid, PSID *Sid);
@ -483,20 +486,21 @@ _dbus_write_socket (DBusSocket fd,
/**
* Closes a file descriptor.
* Closes a socket and invalidates it.
*
* @param fd the file descriptor
* @param error error object
* @returns #FALSE if error set
*/
dbus_bool_t
_dbus_close_socket (DBusSocket fd,
DBusError *error)
_dbus_close_socket (DBusSocket *fd,
DBusError *error)
{
_dbus_assert (fd != NULL);
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
again:
if (closesocket (fd.sock) == SOCKET_ERROR)
if (closesocket (fd->sock) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
@ -505,11 +509,13 @@ _dbus_close_socket (DBusSocket fd,
dbus_set_error (error, _dbus_error_from_errno (errno),
"Could not close socket: socket=%Iu, , %s",
fd.sock, _dbus_strerror_from_errno ());
fd->sock, _dbus_strerror_from_errno ());
_dbus_socket_invalidate (fd);
return FALSE;
}
_dbus_verbose ("socket=%Iu, \n", fd.sock);
_dbus_verbose ("socket=%Iu, \n", fd->sock);
_dbus_socket_invalidate (fd);
return TRUE;
}
@ -1642,7 +1648,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
_dbus_error_from_errno (saved_errno),
"Failed to open socket: %s",
_dbus_strerror (saved_errno));
_dbus_socket_invalidate (&fd);
_dbus_assert (!_dbus_socket_is_valid (fd));
goto out;
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
@ -1650,8 +1656,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (connect (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
{
saved_errno = _dbus_get_low_level_socket_errno ();
closesocket(fd.sock);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
connect_error = dbus_new0 (DBusError, 1);
@ -1698,8 +1703,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (!ret)
{
closesocket (fd.sock);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
goto out;
}
}
@ -1709,8 +1713,7 @@ _dbus_connect_tcp_socket_with_nonce (const char *host,
if (!_dbus_set_socket_nonblocking (fd, error))
{
closesocket (fd.sock);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
goto out;
}
@ -1828,6 +1831,7 @@ _dbus_listen_tcp_socket (const char *host,
_dbus_error_from_errno (saved_errno),
"Failed to open socket: %s",
_dbus_strerror (saved_errno));
_dbus_assert (!_dbus_socket_is_valid (fd));
goto failed;
}
_DBUS_ASSERT_ERROR_IS_CLEAR(error);
@ -1848,7 +1852,7 @@ _dbus_listen_tcp_socket (const char *host,
host ? host : "*", port, _dbus_strerror (saved_errno));
}
if (bind (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
if (bind (fd.sock, (struct sockaddr *) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
{
saved_errno = _dbus_get_low_level_socket_errno ();
closesocket (fd.sock);
@ -2112,6 +2116,56 @@ again:
return TRUE;
}
#ifdef HAVE_AFUNIX_H
/*
* Returns false with no error set if the socket is non-AF_UNIX
* (contrary to our usual convention).
*
* Returns false with an error set on failure to identify it.
*/
static dbus_bool_t
_dbus_socket_is_af_unix (DBusSocket s,
DBusError *error)
{
struct sockaddr_un saddr;
int len;
len = sizeof (saddr);
if (getsockname (s.sock, (struct sockaddr *)&saddr, &len) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to getsockname: %s",
_dbus_strerror_from_errno ());
return FALSE;
}
return saddr.sun_family == AF_UNIX;
}
/**
* @brief return peer process id from Unix domain socket handle
* @param handle AF_UNIX socket descriptor
* @return process id or 0 in case the process id could not be fetched
*/
static dbus_pid_t
_dbus_get_peer_pid_from_uds_handle (int handle)
{
DWORD pid, drc;
if (WSAIoctl (handle, SIO_AF_UNIX_GETPEERPID,
NULL, 0U,
&pid, sizeof (pid), &drc,
NULL, NULL) == SOCKET_ERROR)
{
_dbus_verbose ("failed to get peer's pid\n");
return 0;
}
return pid;
}
#endif
/**
* Reads a single byte which must be nul (an error occurs otherwise),
* and reads unix credentials if available. Fills in pid/uid/gid with
@ -2137,6 +2191,9 @@ _dbus_read_credentials_socket (DBusSocket handle,
{
int bytes_read = 0;
DBusString buf;
#ifdef HAVE_AFUNIX_H
dbus_bool_t uds = FALSE;
#endif
char *sid = NULL;
dbus_pid_t pid;
@ -2153,7 +2210,16 @@ _dbus_read_credentials_socket (DBusSocket handle,
_dbus_string_free (&buf);
}
pid = _dbus_get_peer_pid_from_tcp_handle (handle.sock);
#ifdef HAVE_AFUNIX_H
uds = _dbus_socket_is_af_unix (handle, error);
if (dbus_error_is_set (error))
return FALSE;
if (uds)
pid = _dbus_get_peer_pid_from_uds_handle (handle.sock);
else
#endif
pid = _dbus_get_peer_pid_from_tcp_handle (handle.sock);
if (pid == 0)
return TRUE;
@ -2524,8 +2590,7 @@ _dbus_generate_random_bytes (DBusString *str,
}
/**
* Gets the temporary files directory by inspecting the environment variables
* TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned
* Gets the temporary files directory, using GetTempPath()
*
* @returns location of temp directory, or #NULL if no memory for locking
*/
@ -4408,5 +4473,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 */

View file

@ -212,7 +212,7 @@ dbus_bool_t _dbus_set_socket_nonblocking (DBusSocket fd,
DBusError *error);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_close_socket (DBusSocket fd,
dbus_bool_t _dbus_close_socket (DBusSocket *fd,
DBusError *error);
DBUS_PRIVATE_EXPORT
int _dbus_read_socket (DBusSocket fd,
@ -561,6 +561,18 @@ typedef struct
dbus_bool_t _dbus_stat (const DBusString *filename,
DBusStat *statbuf,
DBusError *error);
DBusSocket _dbus_connect_unix_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
DBusSocket _dbus_listen_unix_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
DBusSocket _dbus_connect_exec (const char *path,
char *const argv[],
DBusError *error);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_socketpair (DBusSocket *fd1,
DBusSocket *fd2,
@ -718,6 +730,20 @@ void _dbus_combine_tcp_errors (DBusList **sources,
const char *port,
DBusError *dest);
/**
* @def _DBUS_MAX_SUN_PATH_LENGTH
*
* Maximum length of the path to a UNIX domain socket,
* sockaddr_un::sun_path member. POSIX requires that all systems
* support at least 100 bytes here, including the nul termination.
* We use 99 for the max value to allow for the nul.
*
* We could probably also do sizeof (addr.sun_path)
* but this way we are the same on all platforms
* which is probably a good idea.
*/
#define _DBUS_MAX_SUN_PATH_LENGTH 99
/** @} */
DBUS_END_DECLS

View file

@ -22,6 +22,9 @@
*/
#include <config.h>
#include <stdio.h>
#include "dbus-internals.h"
#include "dbus-connection-internal.h"
#include "dbus-nonce.h"
@ -1042,8 +1045,7 @@ socket_disconnect (DBusTransport *transport)
free_watches (transport);
_dbus_close_socket (socket_transport->fd, NULL);
_dbus_socket_invalidate (&socket_transport->fd);
_dbus_close_socket (&socket_transport->fd, NULL);
}
static dbus_bool_t
@ -1430,8 +1432,7 @@ _dbus_transport_new_for_tcp_socket (const char *host,
if (transport == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_close_socket (fd, NULL);
_dbus_socket_invalidate (&fd);
_dbus_close_socket (&fd, NULL);
}
return transport;
@ -1502,4 +1503,141 @@ _dbus_transport_open_socket(DBusAddressEntry *entry,
}
}
/**
* Creates a new transport for the given Unix domain socket
* path. This creates a client-side of a transport.
*
* @todo once we add a way to escape paths in a dbus
* address, this function needs to do escaping.
*
* @param path the path to the domain socket.
* @param abstract #TRUE to use abstract socket namespace
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
DBusTransport*
_dbus_transport_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
DBusSocket fd = DBUS_SOCKET_INIT;
DBusTransport *transport;
DBusString address;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!_dbus_string_init (&address))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if ((abstract &&
!_dbus_string_append (&address, "unix:abstract=")) ||
(!abstract &&
!_dbus_string_append (&address, "unix:path=")) ||
!_dbus_string_append (&address, path))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
fd = _dbus_connect_unix_socket (path, abstract, error);
if (!_dbus_socket_is_valid (fd))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed_0;
}
_dbus_verbose ("Successfully connected to unix socket %s\n",
path);
transport = _dbus_transport_new_for_socket (fd, NULL, &address);
if (transport == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_1;
}
_dbus_string_free (&address);
return transport;
failed_1:
_dbus_close_socket (&fd, NULL);
failed_0:
_dbus_string_free (&address);
return NULL;
}
/**
* Opens a UNIX socket transport.
*
* @param entry the address entry to try opening as a unix transport.
* @param transport_p return location for the opened transport
* @param error error to be set
* @returns result of the attempt
*/
DBusTransportOpenResult
_dbus_transport_open_unix_socket (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error)
{
const char *method;
method = dbus_address_entry_get_method (entry);
_dbus_assert (method != NULL);
if (strcmp (method, "unix") == 0)
{
const char *path = dbus_address_entry_get_value (entry, "path");
const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
const char *abstract = dbus_address_entry_get_value (entry, "abstract");
if (tmpdir != NULL)
{
_dbus_set_bad_address (error, NULL, NULL,
"cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on");
return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
}
if (path == NULL && abstract == NULL)
{
_dbus_set_bad_address (error, "unix",
"path or abstract",
NULL);
return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
}
if (path != NULL && abstract != NULL)
{
_dbus_set_bad_address (error, NULL, NULL,
"can't specify both \"path\" and \"abstract\" options in an address");
return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
}
if (path)
*transport_p = _dbus_transport_new_for_domain_socket (path, FALSE,
error);
else
*transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE,
error);
if (*transport_p == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_OK;
}
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
}
}
/** @} */

View file

@ -39,7 +39,13 @@ DBusTransportOpenResult _dbus_transport_open_socket (DBusAddressEntry *e
DBusTransport **transport_p,
DBusError *error);
DBusTransport* _dbus_transport_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
DBusTransportOpenResult _dbus_transport_open_unix_socket (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error);
DBUS_END_DECLS

View file

@ -42,73 +42,6 @@
* @{
*/
/**
* Creates a new transport for the given Unix domain socket
* path. This creates a client-side of a transport.
*
* @todo once we add a way to escape paths in a dbus
* address, this function needs to do escaping.
*
* @param path the path to the domain socket.
* @param abstract #TRUE to use abstract socket namespace
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
DBusTransport*
_dbus_transport_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error)
{
DBusSocket fd = DBUS_SOCKET_INIT;
DBusTransport *transport;
DBusString address;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!_dbus_string_init (&address))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if ((abstract &&
!_dbus_string_append (&address, "unix:abstract=")) ||
(!abstract &&
!_dbus_string_append (&address, "unix:path=")) ||
!_dbus_string_append (&address, path))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
fd.fd = _dbus_connect_unix_socket (path, abstract, error);
if (fd.fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed_0;
}
_dbus_verbose ("Successfully connected to unix socket %s\n",
path);
transport = _dbus_transport_new_for_socket (fd, NULL, &address);
if (transport == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_1;
}
_dbus_string_free (&address);
return transport;
failed_1:
_dbus_close_socket (fd, NULL);
failed_0:
_dbus_string_free (&address);
return NULL;
}
/**
* Creates a new transport for the given binary and arguments. This
* creates a client-side of a transport. The process will be forked
@ -180,8 +113,8 @@ _dbus_transport_new_for_exec (const char *path,
}
}
fd.fd = _dbus_connect_exec (path, argv, error);
if (fd.fd < 0)
fd = _dbus_connect_exec (path, argv, error);
if (!_dbus_socket_is_valid (fd))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed;
@ -202,77 +135,25 @@ _dbus_transport_new_for_exec (const char *path,
return transport;
failed:
if (fd.fd >= 0)
_dbus_close_socket (fd, NULL);
if (_dbus_socket_is_valid (fd))
_dbus_close_socket (&fd, NULL);
_dbus_string_free (&address);
return NULL;
}
/**
* Opens platform specific transport types.
*
* @param entry the address entry to try opening
* @param transport_p return location for the opened transport
* @param error error to be set
* @returns result of the attempt
*/
DBusTransportOpenResult
_dbus_transport_open_platform_specific (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error)
_dbus_transport_open_unixexec (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error)
{
const char *method;
method = dbus_address_entry_get_method (entry);
_dbus_assert (method != NULL);
if (strcmp (method, "unix") == 0)
{
const char *path = dbus_address_entry_get_value (entry, "path");
const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
const char *abstract = dbus_address_entry_get_value (entry, "abstract");
if (tmpdir != NULL)
{
_dbus_set_bad_address (error, NULL, NULL,
"cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on");
return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
}
if (path == NULL && abstract == NULL)
{
_dbus_set_bad_address (error, "unix",
"path or abstract",
NULL);
return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
}
if (path != NULL && abstract != NULL)
{
_dbus_set_bad_address (error, NULL, NULL,
"can't specify both \"path\" and \"abstract\" options in an address");
return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
}
if (path)
*transport_p = _dbus_transport_new_for_domain_socket (path, FALSE,
error);
else
*transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE,
error);
if (*transport_p == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_OK;
}
}
else if (strcmp (method, "unixexec") == 0)
if (strcmp (method, "unixexec") == 0)
{
const char *path;
unsigned i;
@ -346,8 +227,33 @@ _dbus_transport_open_platform_specific (DBusAddressEntry *entry,
return DBUS_TRANSPORT_OPEN_OK;
}
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
}
}
/**
* Opens platform specific transport types.
*
* @param entry the address entry to try opening
* @param transport_p return location for the opened transport
* @param error error to be set
* @returns result of the attempt
*/
DBusTransportOpenResult
_dbus_transport_open_platform_specific (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error)
{
#ifdef DBUS_ENABLE_LAUNCHD
else if (strcmp (method, "launchd") == 0)
const char *method;
method = dbus_address_entry_get_method (entry);
_dbus_assert (method != NULL);
if (strcmp (method, "launchd") == 0)
{
DBusError tmp_error = DBUS_ERROR_INIT;
const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
@ -398,8 +304,8 @@ _dbus_transport_open_platform_specific (DBusAddressEntry *entry,
return DBUS_TRANSPORT_OPEN_OK;
}
}
#endif
else
#endif /* DBUS_ENABLE_LAUNCHD */
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_NOT_HANDLED;

View file

@ -23,15 +23,13 @@
#ifndef DBUS_TRANSPORT_UNIX_H
#define DBUS_TRANSPORT_UNIX_H
#include <dbus/dbus-transport.h>
#include <dbus/dbus-transport-protected.h>
DBUS_BEGIN_DECLS
DBusTransport* _dbus_transport_new_for_domain_socket (const char *path,
dbus_bool_t abstract,
DBusError *error);
DBusTransportOpenResult _dbus_transport_open_unixexec (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error);
DBUS_END_DECLS
#endif /* DBUS_TRANSPORT_UNIX_H */

View file

@ -348,6 +348,10 @@ static const struct {
DBusError *error);
} open_funcs[] = {
{ _dbus_transport_open_socket },
{ _dbus_transport_open_unix_socket },
#ifndef _WIN32
{ _dbus_transport_open_unixexec },
#endif
{ _dbus_transport_open_platform_specific },
{ _dbus_transport_open_autolaunch }
#ifdef DBUS_ENABLE_EMBEDDED_TESTS

View file

@ -3655,18 +3655,14 @@
</para>
<para>
When a socket is opened by the D-Bus library it truncates the path
name right before the first trailing Nul byte. This is true for both
normal paths and abstract paths. Note that this is a departure from
previous versions of D-Bus that would create sockets with a fixed
length path name. Names which were shorter than the fixed length
would be padded by Nul bytes.
When a Unix socket is opened by the D-Bus library, the socket address
length does not include the whole <literal>struct sockaddr_un</literal>,
but only the length of the pathname or abstract string (beside other
fields).
</para>
<para>
Unix domain sockets are not available on Windows.
On all other platforms, they are the recommended transport for
D-Bus, either used alone or in conjunction with
<link linkend="transports-systemd">systemd</link> or
They are the recommended transport for D-Bus, either used alone or in
conjunction with <link linkend="transports-systemd">systemd</link> or
<link linkend="transports-launchd">launchd</link> addresses.
</para>
<para>
@ -3967,14 +3963,6 @@
information on situations where these transports have been used,
and alternatives to these transports.
</para>
<para>
Implementations of D-Bus on Windows operating systems normally
use a nonce-tcp transport via the local loopback interface.
This is because the
<link linkend="transports-unix-domain-sockets">unix</link>
transport, which would otherwise be recommended, is not
available on these operating systems.
</para>
<para>
On start, the server generates a random 16 byte nonce and writes it

View file

@ -607,6 +607,7 @@ foreach function : check_functions
endforeach
check_headers = [
'afunix.h',
'alloca.h',
'byteswap.h',
'crt_externs.h',

View file

@ -86,9 +86,10 @@ setup (Fixture *f,
dbus_error_init (&f->e);
g_queue_init (&f->client_messages);
if ((g_str_has_prefix (addr, "tcp:") ||
g_str_has_prefix (addr, "nonce-tcp:")) &&
!test_check_tcp_works ())
if ((g_str_has_prefix (addr, "unix:") && !test_check_af_unix_works ()) ||
((g_str_has_prefix (addr, "tcp:") ||
g_str_has_prefix (addr, "nonce-tcp:")) &&
!test_check_tcp_works ()))
{
f->skip = TRUE;
return;
@ -406,26 +407,31 @@ main (int argc,
char **argv)
{
int ret;
#ifdef DBUS_UNIX
char *tmp = _dbus_strdup ("/tmp");
#else
char *tmp = dbus_address_escape_value (g_get_tmp_dir ());
#endif
gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp);
test_init (&argc, &argv);
g_test_add ("/corrupt/tcp", Fixture, "tcp:host=127.0.0.1", setup,
test_corrupt, teardown);
#ifdef DBUS_UNIX
g_test_add ("/corrupt/unix", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/corrupt/unix", Fixture, unix_tmpdir, setup,
test_corrupt, teardown);
#endif
g_test_add ("/corrupt/byte-order/tcp", Fixture, "tcp:host=127.0.0.1", setup,
test_byte_order, teardown);
#ifdef DBUS_UNIX
g_test_add ("/corrupt/byte-order/unix", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/corrupt/byte-order/unix", Fixture, unix_tmpdir, setup,
test_byte_order, teardown);
#endif
ret = g_test_run ();
dbus_shutdown ();
g_free (unix_tmpdir);
dbus_free (tmp);
return ret;
}

View file

@ -94,6 +94,10 @@ test_oom_wrapper (gconstpointer data)
{
const OOMTestCase *test = data;
if (g_str_has_prefix (test->data, "unix:") &&
!test_check_af_unix_works ())
return;
if ((g_str_has_prefix (test->data, "tcp:") ||
g_str_has_prefix (test->data, "nonce-tcp:")) &&
!test_check_tcp_works ())
@ -131,6 +135,12 @@ main (int argc,
char **argv)
{
int ret;
#ifdef DBUS_UNIX
char *tmp = _dbus_strdup ("/tmp");
#else
char *tmp = dbus_address_escape_value (g_get_tmp_dir ());
#endif
gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp);
test_init (&argc, &argv);
@ -139,13 +149,13 @@ main (int argc,
add_oom_test ("/server/new-nonce-tcp", test_new_server, "nonce-tcp:host=127.0.0.1,bind=127.0.0.1");
add_oom_test ("/server/new-tcp-star", test_new_server, "tcp:host=127.0.0.1,bind=*");
add_oom_test ("/server/new-tcp-v4", test_new_server, "tcp:host=127.0.0.1,bind=127.0.0.1,family=ipv4");
#ifdef DBUS_UNIX
add_oom_test ("/server/unix", test_new_server, "unix:tmpdir=/tmp");
#endif
add_oom_test ("/server/unix", test_new_server, unix_tmpdir);
ret = g_test_run ();
g_queue_free_full (test_cases_to_free, g_free);
dbus_shutdown ();
g_free (unix_tmpdir);
dbus_free (tmp);
return ret;
}

View file

@ -99,9 +99,10 @@ setup (Fixture *f,
dbus_error_init (&f->e);
g_queue_init (&f->server_messages);
if ((g_str_has_prefix (addr, "tcp:") ||
g_str_has_prefix (addr, "nonce-tcp:")) &&
!test_check_tcp_works ())
if ((g_str_has_prefix (addr, "unix:") && !test_check_af_unix_works ()) ||
((g_str_has_prefix (addr, "tcp:") ||
g_str_has_prefix (addr, "nonce-tcp:")) &&
!test_check_tcp_works ()))
{
f->skip = TRUE;
return;
@ -116,7 +117,6 @@ setup (Fixture *f,
test_server_setup (f->ctx, f->server);
}
#ifdef DBUS_UNIX
static void
setup_runtime (Fixture *f,
gconstpointer addr)
@ -131,6 +131,7 @@ setup_runtime (Fixture *f,
/* we're relying on being single-threaded for this to be safe */
f->saved_runtime_dir = g_strdup (g_getenv ("XDG_RUNTIME_DIR"));
g_setenv ("XDG_RUNTIME_DIR", f->tmp_runtime_dir, TRUE);
g_test_message ("XDG_RUNTIME_DIR %s", f->tmp_runtime_dir);
setup (f, addr);
@ -140,9 +141,12 @@ setup_runtime (Fixture *f,
listening_at = dbus_server_get_address (f->server);
g_test_message ("listening at %s", listening_at);
g_assert (g_str_has_prefix (listening_at, "unix:path="));
#ifndef DBUS_WIN
/* FIXME: on gitlab CI win32, it doesn't use runtime dir, why..? */
g_assert (strstr (listening_at, "dbus%3ddaemon%3dtest.") != NULL);
g_assert (strstr (listening_at, "/bus,") != NULL ||
g_str_has_suffix (listening_at, "/bus"));
g_assert (strstr (listening_at, DBUS_DIR_SEPARATOR_S "bus,") != NULL ||
g_str_has_suffix (listening_at, DBUS_DIR_SEPARATOR_S "bus"));
#endif
dbus_free (listening_at);
}
@ -166,11 +170,12 @@ setup_no_runtime (Fixture *f,
g_test_message ("listening at %s", listening_at);
/* we have fallen back to something in /tmp, either abstract or not */
g_assert (g_str_has_prefix (listening_at, "unix:"));
g_assert (strstr (listening_at, "=/tmp/") != NULL);
#ifdef DBUS_UNIX
g_assert (strstr (listening_at, "=/tmp" DBUS_DIR_SEPARATOR_S) != NULL);
#endif
dbus_free (listening_at);
}
#endif
static void
test_connect (Fixture *f,
@ -221,8 +226,7 @@ test_connect (Fixture *f,
g_assert_cmpstr (dbus_address_entry_get_value (entries[0], "noncefile"),
!=, NULL);
}
#ifdef DBUS_UNIX
else if (g_strcmp0 (listening_address, "unix:tmpdir=/tmp") == 0)
else if (g_str_has_prefix (listening_address, "unix:tmpdir="))
{
g_assert_cmpstr (dbus_address_entry_get_method (entries[0]), ==, "unix");
@ -231,7 +235,7 @@ test_connect (Fixture *f,
const char *abstract = dbus_address_entry_get_value (entries[0],
"abstract");
g_assert_true (g_str_has_prefix (abstract, "/tmp/dbus-"));
g_assert_true (g_str_has_prefix (abstract, "/tmp" DBUS_DIR_SEPARATOR_S "dbus-"));
g_assert_cmpstr (dbus_address_entry_get_value (entries[0], "path"),
==, NULL);
}
@ -241,26 +245,29 @@ test_connect (Fixture *f,
"path");
g_assert_nonnull (path);
g_assert_true (g_str_has_prefix (path, "/tmp/dbus-"));
#ifdef DBUS_UNIX
g_assert_true (g_str_has_prefix (path, "/tmp" DBUS_DIR_SEPARATOR_S "dbus-"));
#endif
}
}
else if (g_strcmp0 (listening_address, "unix:dir=/tmp") == 0)
else if (g_str_has_prefix (listening_address, "unix:dir="))
{
const char *path = dbus_address_entry_get_value (entries[0],
"path");
g_assert_cmpstr (dbus_address_entry_get_method (entries[0]), ==, "unix");
g_assert_nonnull (path);
g_assert_true (g_str_has_prefix (path, "/tmp/dbus-"));
#ifdef DBUS_UNIX
g_assert_true (g_str_has_prefix (path, "/tmp" DBUS_DIR_SEPARATOR_S "dbus-"));
#endif
}
else if (g_strcmp0 (listening_address,
"unix:runtime=yes;unix:tmpdir=/tmp") == 0)
else if (g_str_has_prefix (listening_address,
"unix:runtime=yes;unix:tmpdir="))
{
g_assert_cmpstr (dbus_address_entry_get_method (entries[0]), ==, "unix");
/* No particular statement about the path here: for that see
* setup_runtime() and setup_no_runtime() */
}
#endif
else
{
g_assert_not_reached ();
@ -441,7 +448,6 @@ teardown (Fixture *f,
test_main_context_unref (f->ctx);
}
#ifdef DBUS_UNIX
static void
teardown_no_runtime (Fixture *f,
gconstpointer addr)
@ -479,13 +485,20 @@ teardown_runtime (Fixture *f,
g_free (f->saved_runtime_dir);
g_free (f->tmp_runtime_dir);
}
#endif
int
main (int argc,
char **argv)
{
int ret;
#ifdef DBUS_UNIX
char *tmp = _dbus_strdup ("/tmp");
#else
char *tmp = dbus_address_escape_value (g_get_tmp_dir ());
#endif
gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp);
gchar *unix_dir = g_strdup_printf ("unix:dir=%s", tmp);
gchar *unix_runtime_or_fallback = g_strdup_printf ("unix:runtime=yes;%s", unix_tmpdir);
test_init (&argc, &argv);
@ -502,28 +515,31 @@ main (int argc,
g_test_add ("/message/bad-guid/tcp", Fixture, "tcp:host=127.0.0.1", setup,
test_bad_guid, teardown);
#ifdef DBUS_UNIX
g_test_add ("/connect/unix/tmpdir", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/connect/unix/tmpdir", Fixture, unix_tmpdir, setup,
test_connect, teardown);
g_test_add ("/message/unix/tmpdir", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/message/unix/tmpdir", Fixture, unix_tmpdir, setup,
test_message, teardown);
g_test_add ("/connect/unix/dir", Fixture, "unix:dir=/tmp", setup,
g_test_add ("/connect/unix/dir", Fixture, unix_dir, setup,
test_connect, teardown);
g_test_add ("/message/unix/dir", Fixture, "unix:dir=/tmp", setup,
g_test_add ("/message/unix/dir", Fixture, unix_dir, setup,
test_message, teardown);
g_test_add ("/connect/unix/runtime", Fixture,
"unix:runtime=yes;unix:tmpdir=/tmp", setup_runtime, test_connect,
unix_runtime_or_fallback, setup_runtime, test_connect,
teardown_runtime);
g_test_add ("/connect/unix/no-runtime", Fixture,
"unix:runtime=yes;unix:tmpdir=/tmp", setup_no_runtime, test_connect,
unix_runtime_or_fallback, setup_no_runtime, test_connect,
teardown_no_runtime);
g_test_add ("/message/bad-guid/unix", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/message/bad-guid/unix", Fixture, unix_tmpdir, setup,
test_bad_guid, teardown);
#endif
ret = g_test_run ();
dbus_shutdown ();
g_free (unix_tmpdir);
g_free (unix_dir);
g_free (unix_runtime_or_fallback);
dbus_free (tmp);
return ret;
}

View file

@ -129,9 +129,10 @@ setup (Fixture *f,
dbus_error_init (&f->e);
g_queue_init (&f->messages);
if ((g_str_has_prefix (address, "tcp:") ||
g_str_has_prefix (address, "nonce-tcp:")) &&
!test_check_tcp_works ())
if ((g_str_has_prefix (address, "unix:") && !test_check_af_unix_works ()) ||
((g_str_has_prefix (address, "tcp:") ||
g_str_has_prefix (address, "nonce-tcp:")) &&
!test_check_tcp_works ()))
{
f->skip = TRUE;
return;
@ -338,6 +339,12 @@ main (int argc,
char **argv)
{
int ret;
#ifdef DBUS_UNIX
char *tmp = _dbus_strdup ("/tmp");
#else
char *tmp = dbus_address_escape_value (g_get_tmp_dir ());
#endif
gchar *unix_tmpdir = g_strdup_printf ("unix:tmpdir=%s", tmp);
test_init (&argc, &argv);
@ -348,16 +355,16 @@ main (int argc,
g_test_add ("/limit/tcp", Fixture, "tcp:host=127.0.0.1", setup,
test_limit, teardown);
#ifdef DBUS_UNIX
g_test_add ("/connect/unix", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/connect/unix", Fixture, unix_tmpdir, setup,
test_connect, teardown);
g_test_add ("/relay/unix", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/relay/unix", Fixture, unix_tmpdir, setup,
test_relay, teardown);
g_test_add ("/limit/unix", Fixture, "unix:tmpdir=/tmp", setup,
g_test_add ("/limit/unix", Fixture, unix_tmpdir, setup,
test_limit, teardown);
#endif
ret = g_test_run ();
dbus_shutdown ();
g_free (unix_tmpdir);
dbus_free (tmp);
return ret;
}

View file

@ -899,6 +899,25 @@ test_check_tcp_works (void)
#endif
}
gboolean
test_check_af_unix_works (void)
{
#if defined(G_OS_WIN32) && !defined(HAVE_AFUNIX_H)
/* AFUNIX support is compiled out, skip system check */
return FALSE;
#else
#ifdef G_OS_WIN32
SOCKET fd = socket (AF_UNIX, SOCK_STREAM, 0);
closesocket (fd);
return fd != INVALID_SOCKET;
#else
int fd = socket (AF_UNIX, SOCK_STREAM, 0);
close (fd);
return fd >= 0;
#endif
#endif
}
/*
* Store the result of an async operation. @user_data is a pointer to a
* variable that can store @result, initialized to %NULL.

View file

@ -143,6 +143,7 @@ backported_g_steal_pointer (gpointer pointer_to_pointer)
#endif
gboolean test_check_tcp_works (void);
gboolean test_check_af_unix_works (void);
void test_store_result_cb (GObject *source_object,
GAsyncResult *result,