summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Habacker <ralf.habacker@freenet.de>2018-03-08 17:02:15 +0100
committerRalf Habacker <ralf.habacker@freenet.de>2018-03-08 17:02:15 +0100
commite29d7125963624c36584c448e3207a74de8a1708 (patch)
treedb7772a06a4a2f5b01d3db4c7510e334276a1268
parentca83d577557d99611dcb3e7dcdd43c996555bfe0 (diff)
Use linux related code also on Windows61922
-rw-r--r--cmake/CMakeLists.txt4
-rw-r--r--dbus/dbus-sysdeps-unix.c176
-rw-r--r--dbus/dbus-sysdeps-win.c59
-rw-r--r--dbus/dbus-sysdeps.c177
-rw-r--r--dbus/dbus-sysdeps.h7
5 files changed, 236 insertions, 187 deletions
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 9f0098a1c..9fc76d466 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -170,6 +170,10 @@ if(MSVC)
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /FIconfig.h")
endif()
+# set Windows Vista as mimimun requirement
+if(WIN32 AND NOT WINCE)
+ add_definitions(-D_WIN32_WINNT=0x0600)
+endif()
#
# setup warnings
#
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 336781581..706c909d3 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -1325,182 +1325,6 @@ _dbus_listen_systemd_sockets (DBusSocket **fds,
#endif
}
-/*
- * Try to convert the IPv4 or IPv6 address pointed to by
- * sockaddr_pointer into a string.
- *
- * @param sockaddr_pointer A struct sockaddr_in or struct sockaddr_in6
- * @param len The length of the struct pointed to by sockaddr_pointer
- * @param string An array to write the address into
- * @param string_len Length of string (should usually be at least INET6_ADDRSTRLEN)
- * @param family_name Used to return "ipv4" or "ipv6", or NULL to ignore
- * @param port Used to return the port number, or NULL to ignore
- * @returns #FALSE with errno set if the address family was not understood
- */
-static dbus_bool_t
-inet_sockaddr_to_string (const void *sockaddr_pointer,
- size_t len,
- char *string,
- size_t string_len,
- const char **family_name,
- dbus_uint16_t *port)
-{
- union
- {
- struct sockaddr sa;
- struct sockaddr_storage storage;
- struct sockaddr_in ipv4;
- struct sockaddr_in6 ipv6;
- } addr;
-
- if (len > sizeof (addr))
- return FALSE;
-
- _DBUS_ZERO (addr);
- memcpy (&addr, sockaddr_pointer, len);
-
- switch (addr.sa.sa_family)
- {
- case AF_INET:
- if (inet_ntop (AF_INET, &addr.ipv4.sin_addr, string, string_len) != NULL)
- {
- if (family_name != NULL)
- *family_name = "ipv4";
-
- if (port != NULL)
- *port = ntohs (addr.ipv4.sin_port);
-
- return TRUE;
- }
-
- return FALSE;
-
-#ifdef AF_INET6
- case AF_INET6:
- if (inet_ntop (AF_INET6, &addr.ipv6.sin6_addr, string, string_len) != NULL)
- {
- if (family_name != NULL)
- *family_name = "ipv6";
-
- if (port != NULL)
- *port = ntohs (addr.ipv6.sin6_port);
-
- return TRUE;
- }
- return FALSE;
-#endif
-
- default:
- errno = EAFNOSUPPORT;
- return FALSE;
- }
-}
-
-/*
- * Format an error appropriate for saved_errno for the IPv4 or IPv6
- * address pointed to by sockaddr_pointer of length sockaddr_len.
- *
- * @param error The error to set
- * @param sockaddr_pointer A struct sockaddr_in or struct sockaddr_in6
- * @param len The length of the struct pointed to by sockaddr_pointer
- * @param description A prefix like "Failed to listen on socket"
- * @param saved_errno The OS-level error number to use
- */
-static void
-set_error_with_inet_sockaddr (DBusError *error,
- const void *sockaddr_pointer,
- socklen_t len,
- const char *description,
- int saved_errno)
-{
- char string[INET6_ADDRSTRLEN];
- dbus_uint16_t port;
- const struct sockaddr *addr = sockaddr_pointer;
-
- if (inet_sockaddr_to_string (sockaddr_pointer, len, string, sizeof (string),
- NULL, &port))
- {
- dbus_set_error (error, _dbus_error_from_errno (saved_errno),
- "%s \"%s\" port %u: %s",
- description, string, port, _dbus_strerror (saved_errno));
- }
- else
- {
- dbus_set_error (error, _dbus_error_from_errno (saved_errno),
- "%s <address of unknown family %d>: %s",
- description, addr->sa_family,
- _dbus_strerror (saved_errno));
- }
-}
-
-static void
-combine_tcp_errors (DBusList **sources,
- const char *summary,
- const char *host,
- const char *port,
- DBusError *dest)
-{
- DBusString message = _DBUS_STRING_INIT_INVALID;
-
- if (_dbus_list_length_is_one (sources))
- {
- /* If there was exactly one error, just use it */
- dbus_move_error (_dbus_list_get_first (sources), dest);
- }
- else
- {
- DBusList *iter;
- const char *name;
-
- /* If there was more than one error, concatenate all the
- * errors' diagnostic messages, and use their common error
- * name, or DBUS_ERROR_FAILED if more than one name is
- * represented */
- if (!_dbus_string_init (&message))
- {
- _DBUS_SET_OOM (dest);
- goto out;
- }
-
- for (iter = _dbus_list_get_first_link (sources);
- iter != NULL;
- iter = _dbus_list_get_next_link (sources, iter))
- {
- DBusError *error = iter->data;
-
- if (name == NULL)
- {
- /* no error names known yet, try to use this one */
- name = error->name;
- }
- else if (strcmp (name, error->name) != 0)
- {
- /* errors of two different names exist, reconcile by
- * using FAILED */
- name = DBUS_ERROR_FAILED;
- }
-
- if ((_dbus_string_get_length (&message) > 0 &&
- !_dbus_string_append (&message, "; ")) ||
- !_dbus_string_append (&message, error->message))
- {
- _DBUS_SET_OOM (dest);
- goto out;
- }
- }
-
- if (name == NULL)
- name = DBUS_ERROR_FAILED;
-
- dbus_set_error (dest, name, "%s to \"%s\":%s (%s)",
- summary, host ? host : "*", port,
- _dbus_string_get_const_data (&message));
- }
-
-out:
- _dbus_string_free (&message);
-}
-
/**
* Creates a socket and connects to a socket at the given host
* and port. The connection fd is returned, and is set up as
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index 4e71d1cf2..47e7d514d 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -30,12 +30,6 @@
#define STRSAFE_NO_DEPRECATE
-#ifndef DBUS_WINCE
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#endif
-
#include "dbus-internals.h"
#include "dbus-sha.h"
#include "dbus-sysdeps.h"
@@ -1646,6 +1640,9 @@ _dbus_listen_tcp_socket (const char *host,
DBusSocket **fds_p,
DBusError *error)
{
+ int saved_errno;
+ DBusList *bind_errors = NULL;
+ DBusError *bind_error = NULL;
DBusSocket *listen_fd = NULL;
int nlisten_fd = 0, res, i, port_num = -1;
struct addrinfo hints;
@@ -1722,6 +1719,7 @@ _dbus_listen_tcp_socket (const char *host,
if (bind (fd.sock, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
{
DBUS_SOCKET_SET_ERRNO ();
+ saved_errno = errno;
closesocket (fd.sock);
if (errno == WSAEADDRINUSE)
{
@@ -1732,11 +1730,50 @@ _dbus_listen_tcp_socket (const char *host,
tmp = tmp->ai_next;
continue;
}
- dbus_set_error (error, _dbus_error_from_errno (errno),
- "Failed to bind socket \"%s:%s\": %s",
- host ? host : "*", port, _dbus_strerror_from_errno ());
- goto failed;
- }
+
+ /*
+ * We don't treat this as a fatal error, because there might be
+ * other addresses that we can listen on. In particular:
+ *
+ * - If saved_errno is EADDRINUSE after we
+ * "goto redo_lookup_with_port" after binding a port on one of the
+ * possible addresses, we will try to bind that same port on
+ * every address, including the same address again for a second
+ * time, which will fail with EADDRINUSE.
+ *
+ * - If saved_errno is EADDRINUSE, it might be because binding to
+ * an IPv6 address implicitly binds to a corresponding IPv4
+ * address or vice versa (e.g. Linux with bindv6only=0).
+ *
+ * - If saved_errno is EADDRNOTAVAIL when we asked for family
+ * AF_UNSPEC, it might be because IPv6 is disabled for this
+ * particular interface (e.g. Linux with
+ * /proc/sys/net/ipv6/conf/lo/disable_ipv6).
+ */
+ bind_error = dbus_new0 (DBusError, 1);
+
+ if (bind_error == NULL)
+ {
+ _DBUS_SET_OOM (error);
+ goto failed;
+ }
+
+ dbus_error_init (bind_error);
+ set_error_with_inet_sockaddr (bind_error, tmp->ai_addr, tmp->ai_addrlen,
+ "Failed to bind socket", saved_errno);
+
+ if (!_dbus_list_append (&bind_errors, bind_error))
+ {
+ dbus_error_free (bind_error);
+ dbus_free (bind_error);
+ _DBUS_SET_OOM (error);
+ goto failed;
+ }
+
+ /* Try the next address, maybe it will work better */
+ tmp = tmp->ai_next;
+ continue;
+ }
if (listen (fd.sock, 30 /* backlog */) == SOCKET_ERROR)
{
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 20bb89441..748bda340 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -49,6 +49,7 @@
#ifdef DBUS_WIN
#include <stdlib.h>
+ #include <winsock2.h>
#elif (defined __APPLE__)
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
@@ -773,6 +774,182 @@ _dbus_log (DBusSystemLogSeverity severity,
va_end (args);
}
+/*
+ * Try to convert the IPv4 or IPv6 address pointed to by
+ * sockaddr_pointer into a string.
+ *
+ * @param sockaddr_pointer A struct sockaddr_in or struct sockaddr_in6
+ * @param len The length of the struct pointed to by sockaddr_pointer
+ * @param string An array to write the address into
+ * @param string_len Length of string (should usually be at least INET6_ADDRSTRLEN)
+ * @param family_name Used to return "ipv4" or "ipv6", or NULL to ignore
+ * @param port Used to return the port number, or NULL to ignore
+ * @returns #FALSE with errno set if the address family was not understood
+ */
+static dbus_bool_t
+inet_sockaddr_to_string (const void *sockaddr_pointer,
+ size_t len,
+ char *string,
+ size_t string_len,
+ const char **family_name,
+ dbus_uint16_t *port)
+{
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_storage storage;
+ struct sockaddr_in ipv4;
+ struct sockaddr_in6 ipv6;
+ } addr;
+
+ if (len > sizeof (addr))
+ return FALSE;
+
+ _DBUS_ZERO (addr);
+ memcpy (&addr, sockaddr_pointer, len);
+
+ switch (addr.sa.sa_family)
+ {
+ case AF_INET:
+ if (inet_ntop (AF_INET, &addr.ipv4.sin_addr, string, string_len) != NULL)
+ {
+ if (family_name != NULL)
+ *family_name = "ipv4";
+
+ if (port != NULL)
+ *port = ntohs (addr.ipv4.sin_port);
+
+ return TRUE;
+ }
+
+ return FALSE;
+
+#ifdef AF_INET6
+ case AF_INET6:
+ if (inet_ntop (AF_INET6, &addr.ipv6.sin6_addr, string, string_len) != NULL)
+ {
+ if (family_name != NULL)
+ *family_name = "ipv6";
+
+ if (port != NULL)
+ *port = ntohs (addr.ipv6.sin6_port);
+
+ return TRUE;
+ }
+ return FALSE;
+#endif
+
+ default:
+ errno = EAFNOSUPPORT;
+ return FALSE;
+ }
+}
+
+/*
+ * Format an error appropriate for saved_errno for the IPv4 or IPv6
+ * address pointed to by sockaddr_pointer of length sockaddr_len.
+ *
+ * @param error The error to set
+ * @param sockaddr_pointer A struct sockaddr_in or struct sockaddr_in6
+ * @param len The length of the struct pointed to by sockaddr_pointer
+ * @param description A prefix like "Failed to listen on socket"
+ * @param saved_errno The OS-level error number to use
+ */
+void
+set_error_with_inet_sockaddr (DBusError *error,
+ const void *sockaddr_pointer,
+ socklen_t len,
+ const char *description,
+ int saved_errno)
+{
+ char string[INET6_ADDRSTRLEN];
+ dbus_uint16_t port;
+ const struct sockaddr *addr = sockaddr_pointer;
+
+ if (inet_sockaddr_to_string (sockaddr_pointer, len, string, sizeof (string),
+ NULL, &port))
+ {
+ dbus_set_error (error, _dbus_error_from_errno (saved_errno),
+ "%s \"%s\" port %u: %s",
+ description, string, port, _dbus_strerror (saved_errno));
+ }
+ else
+ {
+ dbus_set_error (error, _dbus_error_from_errno (saved_errno),
+ "%s <address of unknown family %d>: %s",
+ description, addr->sa_family,
+ _dbus_strerror (saved_errno));
+ }
+}
+
+static void
+combine_tcp_errors (DBusList **sources,
+ const char *summary,
+ const char *host,
+ const char *port,
+ DBusError *dest)
+{
+ DBusString message = _DBUS_STRING_INIT_INVALID;
+
+ if (_dbus_list_length_is_one (sources))
+ {
+ /* If there was exactly one error, just use it */
+ dbus_move_error (_dbus_list_get_first (sources), dest);
+ }
+ else
+ {
+ DBusList *iter;
+ const char *name;
+
+ /* If there was more than one error, concatenate all the
+ * errors' diagnostic messages, and use their common error
+ * name, or DBUS_ERROR_FAILED if more than one name is
+ * represented */
+ if (!_dbus_string_init (&message))
+ {
+ _DBUS_SET_OOM (dest);
+ goto out;
+ }
+
+ for (iter = _dbus_list_get_first_link (sources);
+ iter != NULL;
+ iter = _dbus_list_get_next_link (sources, iter))
+ {
+ DBusError *error = iter->data;
+
+ if (name == NULL)
+ {
+ /* no error names known yet, try to use this one */
+ name = error->name;
+ }
+ else if (strcmp (name, error->name) != 0)
+ {
+ /* errors of two different names exist, reconcile by
+ * using FAILED */
+ name = DBUS_ERROR_FAILED;
+ }
+
+ if ((_dbus_string_get_length (&message) > 0 &&
+ !_dbus_string_append (&message, "; ")) ||
+ !_dbus_string_append (&message, error->message))
+ {
+ _DBUS_SET_OOM (dest);
+ goto out;
+ }
+ }
+
+ if (name == NULL)
+ name = DBUS_ERROR_FAILED;
+
+ dbus_set_error (dest, name, "%s to \"%s\":%s (%s)",
+ summary, host ? host : "*", port,
+ _dbus_string_get_const_data (&message));
+ }
+
+out:
+ _dbus_string_free (&message);
+}
+
/** @} end of sysdeps */
/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index 0d1ff7c46..24c1523c4 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -692,6 +692,13 @@ void _dbus_daemon_report_reloading (void);
void _dbus_daemon_report_reloaded (void);
void _dbus_daemon_report_stopping (void);
+DBUS_PRIVATE_EXPORT
+void set_error_with_inet_sockaddr (DBusError *error,
+ const void *sockaddr_pointer,
+ socklen_t len,
+ const char *description,
+ int saved_errno);
+
/** @} */
DBUS_END_DECLS