Skip to content

Commit

Permalink
Merge PR #2512: Plugins: lay the groundwork for using Windows PA plug…
Browse files Browse the repository at this point in the history
…ins on Linux with Wine

This PR implements support for running Windows PA plugins on Linux with Wine.

The existing plugins should, in most cases, be usable without many source changes.

The PR also ports the Rocket League PA plugin for Windows to run on Linux/Wine, as a proof of concept.
  • Loading branch information
mkrautz committed Aug 13, 2016
2 parents 86824a3 + 743f129 commit 2396a99
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 15 deletions.
4 changes: 2 additions & 2 deletions plugins/l4d2/l4d2_linux.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -144,14 +144,14 @@ static int trylock(const std::multimap<std::wstring, unsigned long long int> &pi
return false; return false;
} }


procptr32_t steamclient = getModuleAddr("steamclient.so"); // Retrieve "steamclient.so" module's memory address procptr32_t steamclient = getModuleAddr(L"steamclient.so"); // Retrieve "steamclient.so" module's memory address
// This prevents the plugin from linking to the game in case something goes wrong during module linking. // This prevents the plugin from linking to the game in case something goes wrong during module linking.
if (steamclient == 0) if (steamclient == 0)
return false; return false;


serverid_steamclient = steamclient + 0x118E965; // Module + Server ID offset serverid_steamclient = steamclient + 0x118E965; // Module + Server ID offset


procptr32_t server = getModuleAddr("server.so"); // Retrieve "server.so" module's memory address procptr32_t server = getModuleAddr(L"server.so"); // Retrieve "server.so" module's memory address
// This prevents the plugin from linking to the game in case something goes wrong during module linking. // This prevents the plugin from linking to the game in case something goes wrong during module linking.
if (server == 0) if (server == 0)
return false; return false;
Expand Down
8 changes: 8 additions & 0 deletions plugins/mumble_plugin.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
# define MUMBLE_PLUGIN_CALLING_CONVENTION # define MUMBLE_PLUGIN_CALLING_CONVENTION
#endif #endif


#if defined(__GNUC__)
# define MUMBLE_PLUGIN_EXPORT __attribute__((visibility("default")))
#elif defined(_MSC_VER)
# define MUMBLE_PLUGIN_EXPORT __declspec(dllexport)
#else
# error No MUMBLE_PLUGIN_EXPORT definition available
#endif

// Visual Studio 2008 x86 // Visual Studio 2008 x86
#if _MSC_VER == 1500 && defined(_M_IX86) #if _MSC_VER == 1500 && defined(_M_IX86)
# define MUMBLE_PLUGIN_MAGIC 0xd63ab7ef # define MUMBLE_PLUGIN_MAGIC 0xd63ab7ef
Expand Down
26 changes: 18 additions & 8 deletions plugins/mumble_plugin_linux.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ static inline std::string readAll(std::string fn) {
return content; return content;
} }


static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, std::string mod) { static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, const wchar_t *modname) {
std::wstring modnameWide(modname);
std::string modnameNonWide(modnameWide.begin(), modnameWide.end());

std::stringstream ss; std::stringstream ss;
ss << std::string("/proc/"); ss << std::string("/proc/");
ss << static_cast<unsigned long>(pid); ss << static_cast<unsigned long>(pid);
Expand Down Expand Up @@ -137,7 +140,7 @@ static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, std::string mod) {
size_t lastSlash = pathname.find_last_of('/'); size_t lastSlash = pathname.find_last_of('/');
if (pathname.size() > lastSlash + 1) { if (pathname.size() > lastSlash + 1) {
std::string basename = pathname.substr(lastSlash + 1); std::string basename = pathname.substr(lastSlash + 1);
if (basename == mod) { if (basename == modnameNonWide) {
unsigned long addr = strtoul(baseaddr.c_str(), NULL, 16); unsigned long addr = strtoul(baseaddr.c_str(), NULL, 16);
return addr; return addr;
} }
Expand All @@ -148,7 +151,7 @@ static inline PTR_TYPE_CONCRETE getModuleAddr(pid_t pid, std::string mod) {
return 0; return 0;
} }


static inline PTR_TYPE_CONCRETE getModuleAddr(std::string modname) { static inline PTR_TYPE_CONCRETE getModuleAddr(const wchar_t *modname) {
return getModuleAddr(pPid, modname); return getModuleAddr(pPid, modname);
} }


Expand All @@ -166,6 +169,15 @@ static inline bool peekProc(PTR_TYPE base, void *dest, size_t len) {
return (nread != -1 && static_cast<size_t>(nread) == in.iov_len); return (nread != -1 && static_cast<size_t>(nread) == in.iov_len);
} }


template<class T>
T peekProc(PTR_TYPE base) {
T v = 0;
if (!peekProc(base, reinterpret_cast<T *>(&v), sizeof(T))) {
return 0;
}
return v;
}

template<class T> template<class T>
bool peekProc(PTR_TYPE base, T &dest) { bool peekProc(PTR_TYPE base, T &dest) {
struct iovec in; struct iovec in;
Expand All @@ -181,11 +193,11 @@ bool peekProc(PTR_TYPE base, T &dest) {
return (nread != -1 && static_cast<size_t>(nread) == in.iov_len); return (nread != -1 && static_cast<size_t>(nread) == in.iov_len);
} }


static bool inline initialize(const std::multimap<std::wstring, unsigned long long int> &pids, std::wstring procname, std::wstring modname = NULL) { static bool inline initialize(const std::multimap<std::wstring, unsigned long long int> &pids, const wchar_t *procname, const wchar_t *modname = NULL) {
pModule = 0; pModule = 0;


if (! pids.empty()) { if (! pids.empty()) {
std::multimap<std::wstring, unsigned long long int>::const_iterator iter = pids.find(procname); std::multimap<std::wstring, unsigned long long int>::const_iterator iter = pids.find(std::wstring(procname));


if (iter != pids.end()) if (iter != pids.end())
pPid = static_cast<pid_t>(iter->second); pPid = static_cast<pid_t>(iter->second);
Expand All @@ -198,9 +210,7 @@ static bool inline initialize(const std::multimap<std::wstring, unsigned long lo
if (pPid == 0) if (pPid == 0)
return false; return false;


std::string procnameNonWide(procname.begin(), procname.end()); pModule = getModuleAddr(modname ? modname : procname);
std::string modnameNonWide(modname.begin(), modname.end());
pModule = getModuleAddr((modnameNonWide.size() > 0) ? modnameNonWide : procnameNonWide);


if (pModule == 0) { if (pModule == 0) {
pPid = 0; pPid = 0;
Expand Down
6 changes: 6 additions & 0 deletions plugins/mumble_plugin_win32_32bit.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
#ifndef MUMBLE_MUMBLE_PLUGIN_WIN32_32BIT_H_ #ifndef MUMBLE_MUMBLE_PLUGIN_WIN32_32BIT_H_
#define MUMBLE_MUMBLE_PLUGIN_WIN32_32BIT_H_ #define MUMBLE_MUMBLE_PLUGIN_WIN32_32BIT_H_


#if defined(__linux__)
# include "mumble_plugin_linux_32bit.h"
#else

typedef unsigned long procptr32_t; typedef unsigned long procptr32_t;


#define PTR_TYPE procptr32_t #define PTR_TYPE procptr32_t
#include "mumble_plugin_win32_ptr_type.h" #include "mumble_plugin_win32_ptr_type.h"


#endif #endif

#endif
6 changes: 6 additions & 0 deletions plugins/mumble_plugin_win32_64bit.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
#ifndef MUMBLE_MUMBLE_PLUGIN_WIN32_64BIT_H_ #ifndef MUMBLE_MUMBLE_PLUGIN_WIN32_64BIT_H_
#define MUMBLE_MUMBLE_PLUGIN_WIN32_64BIT_H_ #define MUMBLE_MUMBLE_PLUGIN_WIN32_64BIT_H_


#if defined(__linux__)
#include "mumble_plugin_linux_64bit.h"
#else

typedef unsigned long long procptr64_t; typedef unsigned long long procptr64_t;


#define PTR_TYPE procptr64_t #define PTR_TYPE procptr64_t
#include "mumble_plugin_win32_ptr_type.h" #include "mumble_plugin_win32_ptr_type.h"


#endif #endif

#endif
4 changes: 2 additions & 2 deletions plugins/rl/rl.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ static MumblePlugin2 rlplug2 = {
trylock trylock
}; };


extern "C" __declspec(dllexport) MumblePlugin *getMumblePlugin() { extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin *getMumblePlugin() {
return &rlplug; return &rlplug;
} }


extern "C" __declspec(dllexport) MumblePlugin2 *getMumblePlugin2() { extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin2 *getMumblePlugin2() {
return &rlplug2; return &rlplug2;
} }
7 changes: 4 additions & 3 deletions plugins/rl/rl.pro
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@


include(../plugins.pri) include(../plugins.pri)


TARGET = rl TARGET = rl
SOURCES = rl.cpp linux:TARGET = mumble_paplugin_win32_rl
LIBS += -luser32


SOURCES = rl.cpp
win32:LIBS = -luser32
21 changes: 21 additions & 0 deletions src/mumble/Plugins.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -511,6 +511,27 @@ void Plugins::on_Timer_timeout() {
baseName = firstPart + QLatin1String(".") + completeSuffix; baseName = firstPart + QLatin1String(".") + completeSuffix;
} }


if (baseName == QLatin1String("wine-preloader") || baseName == QLatin1String("wine64-preloader")) {
QFile f(QString(QLatin1String("/proc/%1/cmdline")).arg(entry));
if (f.open(QIODevice::ReadOnly)) {
QByteArray cmdline = f.readAll();
f.close();

int nul = cmdline.indexOf('\0');
if (nul != -1) {
cmdline.truncate(nul);
}

QString exe = QString::fromUtf8(cmdline);
if (exe.contains(QLatin1String("\\"))) {
int lastBackslash = exe.lastIndexOf(QLatin1String("\\"));
if (exe.count() > lastBackslash + 1) {
baseName = exe.mid(lastBackslash + 1);
}
}
}
}

if (!baseName.isEmpty()) { if (!baseName.isEmpty()) {
pids.insert(std::pair<std::wstring, unsigned long long int>(baseName.toStdWString(), pid)); pids.insert(std::pair<std::wstring, unsigned long long int>(baseName.toStdWString(), pid));
} }
Expand Down

0 comments on commit 2396a99

Please sign in to comment.