Commit cf34d59b authored by Philip Withnall's avatar Philip Withnall

Merge branch 'gdbus-win32-no-shortname' into 'master'

gdbusaddress, win32: don't rely on short names

Closes #1566

See merge request !631
parents 00c129f8 2d24ea94
Pipeline #68357 passed with stages
in 16 minutes and 37 seconds
......@@ -31,6 +31,7 @@
#ifdef G_OS_WIN32
#include "glib/glib-private.h"
#include "gdbusprivate.h"
#endif
/* ---------------------------------------------------------------------------------------------------- */
......@@ -2421,6 +2422,14 @@ main (gint argc, gchar *argv[])
ret = 0;
goto out;
}
#ifdef G_OS_WIN32
else if (g_strcmp0 (command, _GDBUS_ARG_WIN32_RUN_SESSION_BUS) == 0)
{
g_win32_run_session_bus (NULL, NULL, NULL, 0);
ret = 0;
goto out;
}
#endif
else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
{
const gchar *completion_line;
......
......@@ -37,8 +37,6 @@
#include "gtask.h"
#include "glib-private.h"
#include "gdbusprivate.h"
#include "giomodule-priv.h"
#include "gdbusdaemon.h"
#include "gstdio.h"
#ifdef G_OS_UNIX
......@@ -50,8 +48,6 @@
#ifdef G_OS_WIN32
#include <windows.h>
#include <io.h>
#include <conio.h>
#endif
#include "glibintl.h"
......@@ -1195,325 +1191,12 @@ get_session_address_dbus_launch (GError **error)
/* end of G_OS_UNIX case */
#elif defined(G_OS_WIN32)
#define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
#define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
#define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
#define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
static void
release_mutex (HANDLE mutex)
{
ReleaseMutex (mutex);
CloseHandle (mutex);
}
static HANDLE
acquire_mutex (const char *mutexname)
{
HANDLE mutex;
DWORD res;
mutex = CreateMutexA (NULL, FALSE, mutexname);
if (!mutex)
return 0;
res = WaitForSingleObject (mutex, INFINITE);
switch (res)
{
case WAIT_ABANDONED:
release_mutex (mutex);
return 0;
case WAIT_FAILED:
case WAIT_TIMEOUT:
return 0;
}
return mutex;
}
static gboolean
is_mutex_owned (const char *mutexname)
{
HANDLE mutex;
gboolean res = FALSE;
mutex = CreateMutexA (NULL, FALSE, mutexname);
if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
res = TRUE;
else
ReleaseMutex (mutex);
CloseHandle (mutex);
return res;
}
static char *
read_shm (const char *shm_name)
{
HANDLE shared_mem;
char *shared_data;
char *res;
int i;
res = NULL;
for (i = 0; i < 20; i++)
{
shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
if (shared_mem != 0)
break;
Sleep (100);
}
if (shared_mem != 0)
{
shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
if (shared_data != NULL)
{
res = g_strdup (shared_data);
UnmapViewOfFile (shared_data);
}
CloseHandle (shared_mem);
}
return res;
}
static HANDLE
set_shm (const char *shm_name, const char *value)
{
HANDLE shared_mem;
char *shared_data;
shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, strlen (value) + 1, shm_name);
if (shared_mem == 0)
return 0;
shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
if (shared_data == NULL)
return 0;
strcpy (shared_data, value);
UnmapViewOfFile (shared_data);
return shared_mem;
}
/* These keep state between publish_session_bus and unpublish_session_bus */
static HANDLE published_daemon_mutex;
static HANDLE published_shared_mem;
static gboolean
publish_session_bus (const char *address)
{
HANDLE init_mutex;
init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
{
release_mutex (init_mutex);
CloseHandle (published_daemon_mutex);
published_daemon_mutex = NULL;
return FALSE;
}
published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
if (!published_shared_mem)
{
release_mutex (init_mutex);
CloseHandle (published_daemon_mutex);
published_daemon_mutex = NULL;
return FALSE;
}
release_mutex (init_mutex);
return TRUE;
}
static void
unpublish_session_bus (void)
{
HANDLE init_mutex;
init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
CloseHandle (published_shared_mem);
published_shared_mem = NULL;
release_mutex (published_daemon_mutex);
published_daemon_mutex = NULL;
release_mutex (init_mutex);
}
static void
wait_console_window (void)
{
FILE *console = fopen ("CONOUT$", "w");
SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
fprintf (console, _("(Type any character to close this window)\n"));
fflush (console);
_getch ();
}
static void
open_console_window (void)
{
if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
(HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
{
if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
freopen ("CONOUT$", "w", stdout);
if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
freopen ("CONOUT$", "w", stderr);
SetConsoleTitleW (L"gdbus-daemon debug output.");
atexit (wait_console_window);
}
}
static void
idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
{
GMainLoop *loop = user_data;
g_main_loop_quit (loop);
}
/* Satisfies STARTF_FORCEONFEEDBACK */
static void
turn_off_the_starting_cursor (void)
{
MSG msg;
BOOL bRet;
PostQuitMessage (0);
while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0)
{
if (bRet == -1)
continue;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
__declspec(dllexport) void CALLBACK g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow);
__declspec(dllexport) void CALLBACK
g_win32_run_session_bus (HWND hwnd, HINSTANCE hinst, char *cmdline, int nCmdShow)
{
GDBusDaemon *daemon;
GMainLoop *loop;
const char *address;
GError *error = NULL;
turn_off_the_starting_cursor ();
if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
open_console_window ();
loop = g_main_loop_new (NULL, FALSE);
address = "nonce-tcp:";
daemon = _g_dbus_daemon_new (address, NULL, &error);
if (daemon == NULL)
{
g_printerr ("Can't init bus: %s\n", error->message);
g_error_free (error);
return;
}
g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
if (publish_session_bus (_g_dbus_daemon_get_address (daemon)))
{
g_main_loop_run (loop);
unpublish_session_bus ();
}
g_main_loop_unref (loop);
g_object_unref (daemon);
}
static gchar *
get_session_address_dbus_launch (GError **error)
{
HANDLE autolaunch_mutex, init_mutex;
char *address = NULL;
wchar_t gio_path[MAX_PATH+1+200];
autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
if (is_mutex_owned (DBUS_DAEMON_MUTEX))
address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
release_mutex (init_mutex);
if (address == NULL)
{
gio_path[MAX_PATH] = 0;
if (GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH))
{
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOW si = { 0 };
BOOL res;
wchar_t gio_path_short[MAX_PATH];
wchar_t rundll_path[MAX_PATH*2];
wchar_t args[MAX_PATH*4];
GetShortPathNameW (gio_path, gio_path_short, MAX_PATH);
GetWindowsDirectoryW (rundll_path, MAX_PATH);
wcscat (rundll_path, L"\\rundll32.exe");
if (GetFileAttributesW (rundll_path) == INVALID_FILE_ATTRIBUTES)
{
GetSystemDirectoryW (rundll_path, MAX_PATH);
wcscat (rundll_path, L"\\rundll32.exe");
}
wcscpy (args, L"\"");
wcscat (args, rundll_path);
wcscat (args, L"\" ");
wcscat (args, gio_path_short);
#if defined(_WIN64) || defined(_M_X64) || defined(_M_AMD64)
wcscat (args, L",g_win32_run_session_bus");
#elif defined (_MSC_VER)
wcscat (args, L",_g_win32_run_session_bus@16");
#else
wcscat (args, L",g_win32_run_session_bus@16");
#endif
res = CreateProcessW (rundll_path, args,
0, 0, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
0, NULL /* TODO: Should be root */,
&si, &pi);
if (res)
address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
}
}
release_mutex (autolaunch_mutex);
if (address == NULL)
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Session dbus not running, and autolaunch failed"));
return address;
return _g_dbus_win32_get_session_address_dbus_launch (error);
}
#else /* neither G_OS_UNIX nor G_OS_WIN32 */
static gchar *
get_session_address_dbus_launch (GError **error)
......
......@@ -33,6 +33,8 @@
#include "gdbusproxy.h"
#include "gdbuserror.h"
#include "gdbusintrospection.h"
#include "gdbusdaemon.h"
#include "giomodule-priv.h"
#include "gtask.h"
#include "ginputstream.h"
#include "gmemoryinputstream.h"
......@@ -51,6 +53,8 @@
#ifdef G_OS_WIN32
#include <windows.h>
#include <io.h>
#include <conio.h>
#endif
#include "glibintl.h"
......@@ -2054,6 +2058,357 @@ out:
CloseHandle (h);
return ret;
}
#define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo"
#define DBUS_DAEMON_MUTEX "DBusDaemonMutex"
#define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex"
#define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex"
static void
release_mutex (HANDLE mutex)
{
ReleaseMutex (mutex);
CloseHandle (mutex);
}
static HANDLE
acquire_mutex (const char *mutexname)
{
HANDLE mutex;
DWORD res;
mutex = CreateMutexA (NULL, FALSE, mutexname);
if (!mutex)
return 0;
res = WaitForSingleObject (mutex, INFINITE);
switch (res)
{
case WAIT_ABANDONED:
release_mutex (mutex);
return 0;
case WAIT_FAILED:
case WAIT_TIMEOUT:
return 0;
}
return mutex;
}
static gboolean
is_mutex_owned (const char *mutexname)
{
HANDLE mutex;
gboolean res = FALSE;
mutex = CreateMutexA (NULL, FALSE, mutexname);
if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
res = TRUE;
else
ReleaseMutex (mutex);
CloseHandle (mutex);
return res;
}
static char *
read_shm (const char *shm_name)
{
HANDLE shared_mem;
char *shared_data;
char *res;
int i;
res = NULL;
for (i = 0; i < 20; i++)
{
shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name);
if (shared_mem != 0)
break;
Sleep (100);
}
if (shared_mem != 0)
{
shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
/* It looks that a race is possible here:
* if the dbus process already created mapping but didn't fill it
* the code below may read incorrect address.
* Also this is a bit complicated by the fact that
* any change in the "synchronization contract" between processes
* should be accompanied with renaming all of used win32 named objects:
* otherwise libgio-2.0-0.dll of different versions shipped with
* different apps may break each other due to protocol difference.
*/
if (shared_data != NULL)
{
res = g_strdup (shared_data);
UnmapViewOfFile (shared_data);
}
CloseHandle (shared_mem);
}
return res;
}
static HANDLE
set_shm (const char *shm_name, const char *value)
{
HANDLE shared_mem;
char *shared_data;
shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, strlen (value) + 1, shm_name);
if (shared_mem == 0)
return 0;
shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
if (shared_data == NULL)
return 0;
strcpy (shared_data, value);
UnmapViewOfFile (shared_data);
return shared_mem;
}
/* These keep state between publish_session_bus and unpublish_session_bus */
static HANDLE published_daemon_mutex;
static HANDLE published_shared_mem;
static gboolean
publish_session_bus (const char *address)
{
HANDLE init_mutex;
init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX);
if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
{
release_mutex (init_mutex);
CloseHandle (published_daemon_mutex);
published_daemon_mutex = NULL;
return FALSE;
}
published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
if (!published_shared_mem)
{
release_mutex (init_mutex);
CloseHandle (published_daemon_mutex);
published_daemon_mutex = NULL;
return FALSE;
}
release_mutex (init_mutex);
return TRUE;
}
static void
unpublish_session_bus (void)
{
HANDLE init_mutex;
init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
CloseHandle (published_shared_mem);
published_shared_mem = NULL;
release_mutex (published_daemon_mutex);
published_daemon_mutex = NULL;
release_mutex (init_mutex);
}
static void
wait_console_window (void)
{
FILE *console = fopen ("CONOUT$", "w");
SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
fprintf (console, _("(Type any character to close this window)\n"));
fflush (console);
_getch ();
}
static void
open_console_window (void)
{
if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
(HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
{
if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
freopen ("CONOUT$", "w", stdout);
if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
freopen ("CONOUT$", "w", stderr);
SetConsoleTitleW (L"gdbus-daemon debug output.");
atexit (wait_console_window);
}
}
static void
idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
{
GMainLoop *loop = user_data;
g_main_loop_quit (loop);
}
/* Satisfies STARTF_FORCEONFEEDBACK */
static void
turn_off_the_starting_cursor (void)
{
MSG msg;
BOOL bRet;
PostQuitMessage (0);
while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0)
{
if (bRet == -1)
continue;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
__declspec(dllexport) void __stdcall
g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdshow)
{
GDBusDaemon *daemon;
GMainLoop *loop;
const char *address;
GError *error = NULL;
turn_off_the_starting_cursor ();
if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
open_console_window ();
address = "nonce-tcp:";
daemon = _g_dbus_daemon_new (address, NULL, &error);
if (daemon == NULL)
{
g_printerr ("Can't init bus: %s\n", error->message);
g_error_free (error);
return;
}
loop = g_main_loop_new (NULL, FALSE);
/* There is a subtle detail with "idle-timeout" signal of dbus daemon:
* It is fired on idle after last client disconnection,
* but (at least with glib 2.59.1) it is NEVER fired
* if no clients connect to daemon at all.
* This may lead to infinite run of this daemon process.
*/
g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
if (publish_session_bus (_g_dbus_daemon_get_address (daemon)))
{
g_main_loop_run (loop);
unpublish_session_bus ();
}
g_main_loop_unref (loop);
g_object_unref (daemon);
}
static gboolean autolaunch_binary_absent = FALSE;
gchar *
_g_dbus_win32_get_session_address_dbus_launch (GError **error)
{
HANDLE autolaunch_mutex, init_mutex;
char *address = NULL;
autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
if (is_mutex_owned (DBUS_DAEMON_MUTEX))
address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
release_mutex (init_mutex);
if (address == NULL && !autolaunch_binary_absent)
{
wchar_t gio_path[MAX_PATH + 2] = { 0 };
int gio_path_len = GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH + 1);
/* The <= MAX_PATH check prevents truncated path usage */
if (gio_path_len > 0 && gio_path_len <= MAX_PATH)
{
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOW si = { 0 };
BOOL res = FALSE;
wchar_t exe_path[MAX_PATH + 100] = { 0 };
/* calculate index of first char of dll file name inside full path */
int gio_name_index = gio_path_len;
for (; gio_name_index > 0; --gio_name_index)
{
wchar_t prev_char = gio_path[gio_name_index - 1];
if (prev_char == L'\\' || prev_char == L'/')
break;
}
gio_path[gio_name_index] = L'\0';
wcscpy (exe_path, gio_path);
wcscat (exe_path, L"\\gdbus.exe");
if (GetFileAttributesW (exe_path) == INVALID_FILE_ATTRIBUTES)
{
/* warning won't be raised another time
* since autolaunch_binary_absent would be already set.
*/
autolaunch_binary_absent = TRUE;
g_warning ("win32 session dbus binary not found: %S", exe_path );
}
else
{
wchar_t args[MAX_PATH*2 + 100] = { 0 };
wcscpy (args, L"\"");
wcscat (args, exe_path);
wcscat (args, L"\" ");
#define _L_PREFIX_FOR_EXPANDED(arg) L##arg
#define _L_PREFIX(arg) _L_PREFIX_FOR_EXPANDED (arg)
wcscat (args, _L_PREFIX (_GDBUS_ARG_WIN32_RUN_SESSION_BUS));
#undef _L_PREFIX
#undef _L_PREFIX_FOR_EXPANDED
res = CreateProcessW (exe_path, args,
0, 0, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
0, gio_path,
&si, &pi);
}
if (res)
{
address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
if (address == NULL)
g_warning ("%S dbus binary failed to launch bus, maybe incompatible version", exe_path );
}
}
}
release_mutex (autolaunch_mutex);
if (address == NULL)
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
_("Session dbus not running, and autolaunch failed"));